"Tr" gibi karakterleri çevirmek için "sed" i kullanabilir miyim?


14

Karakter kümesini başka bir kümedeki karşılık gelen karakterlerle değiştirmek istiyorum, şöyle bir şey:

original set: ots
"target" set: u.x

foobartest → fuubar.ex.

Bunun gibi çeviriler / çeviriler trkomutun uzmanlığıdır :

$ echo 'foobartest' | tr 'ots' 'u.x'
fuubar.ex.

Maalesef tr, yerinde olduğu gibi dosyaları değiştirmeyi desteklemiyor sed.
Kullanmak istiyorum, sedbu yüzden geçici dosyaları hokkabazlık tekerleğini yeniden icat etmek zorunda değilim.


"Sed translate character" için herhangi bir sonuç bulamadığım için bu soruyu kendi kendinize yanıtladım. Sihirli anahtar kelime "transliterasyon" olarak sonuçlandı, ancak bu özelliği olabildiğince kolayca bulunabilir hale getirmeye değer olduğunu düşündüm.
n.st

Bunun için geçici çözümler uygulamaya çalışırken akılda tutulması gereken bir şey: tr(doğru) değiştirme kümelerindeki özyinelemeyi yok sayar: echo 'abc' | tr ab bxbxc. İlkel bir çözüm xxc, daha önce çevrilmiş olan karakterlere çeviriyi yeniden uyguladığı için bunu kasaplayabilir.
n.st

İlgili: unicode karakterler için tr analog? (GNU'nun sedaksine GNU trçok baytlı karakterleri translitüre edebilir)
Stéphane Chazelas

Başka bir olasılık istiyorsanız: perl çeviri yapabilir ve -i ve (eski değilse) multibyte. POSIX değil, oldukça yaygın.
dave_thompson_085

Yanıtlar:


24

sedaşağıdaki ygibi çalışan bir komuta sahiptir tr:

$ echo 'foobartest' | sed 'y/ots/u.x/'
fuubar.ex.

yKomut parçasıdır POSIX sedşartname sadece herhangi bir platformda yaklaşık çalışması gerekir böylece.

Ve bu nedenle sed, bir dosyayı düzenlenmiş sürümüyle değiştirerek, rahatsız edici geçici dosya işini kurtarabilirsiniz ( POSIX tarafından belirtilmeyen seçeneği seddesteklemeniz durumunda -i):

$ sed -i 'y/ots/u.x/' some-file.txt

@ StéphaneChazelas Bunu işaret ettiğiniz için teşekkür ederiz; Şimdiye kadar iç çalışmaların farkında değildim. Bundan bahsetmek için cevabımı düzenledim.
n.st

Teşekkürler, bu olağanüstü yararlı! Ben VIM (CentOS 7.3 üzerinde 8.0.1092) çalışmak için bekliyordum ama değil. Sed hiçbir şey yapmamalı mı, VIM mi?
dotancohen

1
@dotancohen Sadece Vim'in yerine koyma işlevi seddiğer işlevlerden sonra modellenmiş olduğu için diğer işlevlerin de olduğu anlamına gelmez. ;) Vim posta listesi, eşdeğerini bulma konusunda bir konuya sahiptir y/abc/def/; en iyi seçenek gibi görünüyor :%call setline(".", tr(getline("."),"abc","def")).
n.st

8

Sizin durumunuzda olduğu gibi, karakterleri boyutlarını değiştirmeden dönüştürüyorsanız (yine de, GNU gibi bazı uygulamalar trsadece tek baytlı karakterleri destekler), şunları yapabilirsiniz:

tr 'ots' 'u.x' < file 1<> file

Yani, trdosyanın üzerine yaz.

Bu sed -i, birkaç hesaptan daha iyidir :

  • fazladan disk alanına ihtiyaç duymaz (bazı seyrek dosyalar, üzerine yazma özel durumlar hariç)
  • inode numaralarını, sahipliği, izinleri, EKL'leri korur ...
  • sembollerle sorunsuz çalışır, zor bağlantıları koparmaz
  • öldürüldüğünde geçici dosyaları yalan söylemez.

Bir dezavantajı, kesintiye uğrarsa, dosya yarıya çevrilecek (bu durumda, bitirmek için tekrar çalıştırabilirsiniz). Bazı seduygulamalar, komut başarılı olmadıkça orijinal dosyanın değişmeden kalmasını sağlayarak bunu doğru şekilde işleyebilir.


3
Çeviri kümelerinde özyineleme varsa çeviriyi yeniden çalıştırmaya dikkat edin, örn echo 'abc' | tr ab bx.
n.st

1
@ n.st, evet, bu yüzden dedim ki , bu durumda demeye değer.
Stéphane Chazelas

Sonunda, geçici dosyalarla çalışmak zorunda kaldım: gist.github.com/n-st/048facd0c12f105ac122030fb58b962f - Çok baytlı karakterler GNU kullanmayı imkansız hale getirdi trve symlink-heavy PXE ortamımızda sed -ibir vidalama bekliyordu olmak…: /
n.st

@ n.st, iconv -t cp437bunun için daha uygun görünüyor.
Stéphane Chazelas

iconvgirdi dosyası zaten cp437 kodlu bayt veya birden çok kodlamanın bir karışımını içerdiğinde kırılır. Bu nedenle, genel durumda tercih edilebilir olsa da, bu durumda manuel değiştirme yapmak daha sağlamdır.
n.st

4

Başka bir alternatif olarak, asıl sorununuz, dosyaları yerinde değiştirme desteğinin olmamasıysa sponge, moreutils paketinden araçla ilgilenebilirsiniz :

tr 'ots' 'u.x' < file | sponge file

yazılır file, ancak yalnızca filegiriş tamamlandığında yazmaya açılır . Gönderen man :

spongestandart girdiyi okur ve belirtilen dosyaya yazar. Kabuk yönlendirmesinden farklı olarak, sünger çıktı dosyasını açmadan önce tüm girdilerini emer. Bu, aynı dosyadan okunan ve aynı dosyaya yazan boru hatlarının oluşturulmasına izin verir.

Bellekte tutulamayan gerçekten büyük dosyalarınız yoksa, spongesizin için çalışabilir.


2
Bir konu spongehala üzerine yazar olmasıdır fileeğer tr(sen yazma olsaydı mesela ama okuma erişimi olmayan başarısız file)
Stéphane Chazelas

Gerçekten de öyle; Bunu beklemiyordum. Teşekkürler.
mindriot

cat file >; fileÇıkışı, yalnızca komut başarılı olduğunda (ancak sed -iorijinalin üzerine yazmak yerine yeni bir dosya oluşturan) yeniden adlandırılan bir geçici dosyaya yazan ksh93 operatörüne bakın .
Stéphane Chazelas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.