Czy mogę używać „sed” do tłumaczenia znaków takich jak „tr”?


14

Chciałbym zastąpić zestaw znaków odpowiednimi znakami z innego zestawu, coś takiego:

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

foobartest → fuubar.ex.

Tłumaczenia / transliteracje takie jak ta są specjalnością trpolecenia:

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

Niestety trnie obsługuje zmiany plików w miejscu, tak jak sedrobi.
Chciałbym użyć, sedwięc nie muszę ponownie wymyślać koła plików tymczasowych żonglerki.


Odpowiedzi na to pytanie, ponieważ nie mogłem znaleźć żadnych wyników dla „sed tłumaczyć znaki”. Magiczne słowo kluczowe stało się „transliteracyjne”, ale pomyślałem, że warto sprawić, by ta funkcja była jak najłatwiej dostępna.
n.

O czym należy pamiętać przy próbie zaimplementowania obejścia tego problemu: tr(poprawnie) ignoruje rekurencję w zestawach zastępczych: echo 'abc' | tr ab bxbxc. Prymitywne rozwiązanie może to zaszkodzić, xxcponieważ ponownie stosuje tłumaczenie do znaków, które już zostały przetłumaczone.
n.

Powiązane: tr analogowy dla znaków Unicode? (GNU w sedprzeciwieństwie do GNU trpotrafi transliterować znaki wielobajtowe)
Stéphane Chazelas,

Jeśli chcesz innej możliwości: perl potrafi tłumaczyć i -i oraz (chyba że starożytny) wielobajtowy. Nie POSIX, ale dość powszechne.
dave_thompson_085

Odpowiedzi:


24

sedma ypolecenie, które działa tak jak tr:

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

yKomenda jest częścią POSIX sedspecyfikacja , więc powinien działać na prawie każdej platformie.

A skoro tak sed, możesz poprosić go o zastąpienie pliku edytowaną wersją, oszczędzając ci kłopotliwego biznesu plików tymczasowych (pod warunkiem, że twoja implementacja sedobsługuje -iopcję, która nie jest określona przez POSIX):

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

@ StéphaneChazelas Dzięki za wskazanie tego; Do tej pory nie byłem świadomy wewnętrznych mechanizmów. Zredagowałem swoją odpowiedź, aby o tym wspomnieć.
n.

Dzięki, jest to niezwykle przydatne! Spodziewałem się, że zadziała w VIM (8.0.1092 na CentOS 7.3), ale nie działa. Czy VIM nie powinien nic robić?
dotancohen

1
@dotancohen To, że funkcja podstawienia Vima jest modelowana na podstawiesed „s”, nie oznacza, że ​​inne funkcje również są. ;) Na liście mailingowej Vima znajduje się wątek na temat znalezienia y/abc/def/odpowiednika; najlepsza opcja wydaje się być :%call setline(".", tr(getline("."),"abc","def")).
n.st

8

Jeśli tak jak w twoim przypadku, transliterujesz znaki bez zmiany ich rozmiaru (zresztą niektóre implementacje, takie jak GNU, trobsługują tylko znaki jednobajtowe), możesz:

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

Oznacza to, że trnadpisują plik nad sobą.

To lepiej niż sed -ina kilku kontach:

  • nie potrzebuje dodatkowego miejsca na dysku (z wyjątkiem niektórych rzadkich plików, specjalnych przypadków kopiowania przy zapisie)
  • zachowuje numery i-węzłów, własność, uprawnienia, listy ACL ...
  • działa OK z linkami symbolicznymi, nie przerywa twardych linków
  • nie pozostawia plików tymczasowych leżących, gdy są zabite.

Wadą jest to, że jeśli zostanie przerwany, plik zostanie w połowie przetłumaczony (w tym przypadku można go jednak uruchomić ponownie, aby go zakończyć). Niektóre sedimplementacje poradziłyby sobie z tym poprawnie, upewniając się, że oryginalny plik pozostaje niezmieniony, chyba że polecenie się powiedzie.


3
Zachowaj ostrożność, ponownie uruchamiając tłumaczenie, jeśli masz rekurencję w zestawach tłumaczeń, np echo 'abc' | tr ab bx.
n.

1
@ n.st, tak, dlatego powiedziałem w tym przypadku , chociaż zgadzam się, że warto to przeliterować.
Stéphane Chazelas,

W końcu musiałem przecież pracować z plikami tymczasowymi: gist.github.com/n-st/048facd0c12f105ac122030fb58b962f - Znaki wielobajtowe uniemożliwiały korzystanie z GNU, tra w naszym środowisku PXE o dużym obciążeniu symbolicznym sed -iczekanie się wydarzy…: /
n. 1.

@ n.st, iconv -t cp437wydaje się bardziej odpowiednie do tego.
Stéphane Chazelas,

iconvpęka, gdy plik wejściowy zawiera już bajty zakodowane w cp437 lub mieszaninę wielu kodowań. Chociaż jest to preferowane w ogólnym przypadku, bardziej niezawodne jest ręczne zastępowanie w tym przypadku.
n.st

4

Jako kolejną alternatywę, jeśli twoim głównym problemem jest brak obsługi zmiany plików w miejscu, możesz zainteresować się spongenarzędziem z pakietu moreutils :

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

zapisze do file, ale będzie otwarty filedo zapisu po zakończeniu wprowadzania danych. Z strony podręcznika :

spongeodczytuje standardowe wejście i zapisuje je w określonym pliku. W przeciwieństwie do przekierowania powłoki, gąbka wchłania wszystkie dane wejściowe przed otwarciem pliku wyjściowego. Umożliwia to tworzenie potoków, które odczytują i zapisują do tego samego pliku.

O ile nie masz naprawdę dużych plików, których nie można przechowywać w pamięci, spongemoże Ci pomóc.


2
Jednym z problemów spongejest to, że nadal się zastępuje, filejeśli się trnie powiedzie (na przykład, jeśli miałeś dostęp do zapisu, ale nie masz dostępu do odczytu file)
Stéphane Chazelas

Och, rzeczywiście tak jest; Nie spodziewałem się tego. Dzięki.
mindriot

Zobacz cat file >; fileoperator ksh93, który zapisuje dane wyjściowe do pliku tymczasowego, którego nazwa zostaje zmieniona na miejsce docelowe tylko wtedy, gdy polecenie się powiedzie (ale jak to sed -i, że tworzy nowy plik zamiast nadpisywania oryginału).
Stéphane Chazelas,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.