Jak znaleźć i zamienić ciąg bez użycia polecenia Sed?


16

Jak wszyscy wiemy, sedjest wielce skuteczny, aby znaleźć i zastąpić ciąg, na przykład znaleziska „A” i zastąpienie go do „B” sed 's/a/b/g'.

Czy można to zrobić za pomocą innego polecenia lub skryptu powłoki zamiast sed?

Dotyczy to przyciętych systemów Linux dla telewizorów, które nie mają sedpolecenia. Więc muszę użyć innych poleceń lub skryptów zamiastsed 's/a/b/g'. –


W rzeczywistości jest to podstawienie oparte na wyrażeniach regularnych. Każde narzędzie lub język zdolny obsłużyć coś takiego będzie w stanie zrobić to samo, ale z różną składnię: $var=~s/a/b/g, gsub(/a/,"b",var), var.gsub(/a/,'b'), var.replace(/a/g,'b'), preg_replace("/a/","b",$var), regsub -all a b $var. Poza tym wiele narzędzi i języków może również zastępować ciągi tekstowe. Więc twoje pytanie jest jakoś szerokie.
manatwork

1
Dlaczego? Jaki problem próbujesz rozwiązać?
Gilles „SO- przestań być zły”

Przycięte systemy linuksowe dla TV nie mają polecenia. Więc muszę użyć innej komendy lub skryptu, aby zamiast sed 's / a / b / g'.
binghenzq

Odpowiedzi:


12

Tak, istnieje wiele sposobów na zrobienie tego. Możesz również użyć awk, perllub, bashaby wykonać te czynności. Zasadniczo sedjest to jednak prawdopodobnie najbardziej odpowiednie narzędzie do wykonywania tego typu zadań.

Przykłady

Powiedzmy, że mam te przykładowe dane w pliku data.txt:

foo bar 12,300.50
foo bar 2,300.50
abc xyz 1,22,300.50

awk

$ awk '{gsub("foo", "foofoofoo", $0); print}' data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

Perl

$ perl -pe "s/foo/foofoofoo/g" data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

Edycja bezpośrednia

Powyższe przykłady mogą również bezpośrednio modyfikować pliki. Przykład Perla jest trywialny. Po prostu dodaj -iprzełącznik.

$ perl -pie "s/foo/foofoofoo/g" data.txt 

Dla awkniego jest trochę mniej bezpośredni, ale równie skuteczne:

$ { rm data.txt && awk '{gsub("foo", "foofoofoo", $0); print}' > data.txt; } < data.txt

Ta metoda tworzy podpowłokę z nawiasami klamrowymi {...}, w których plik jest przekierowywany do niego przez to:

$ { ... } < data.txt

Po przekierowaniu pliku do podpowłoki jest on usuwany, a następnie awkuruchamiany względem zawartości pliku, który został odczytany do podpowłoki STDIN. Ta treść jest następnie przetwarzana awki zapisywana z powrotem do tej samej nazwy pliku, którą właśnie usunęliśmy, skutecznie ją zastępując.


Dziękuję za odpowiedź i spróbuję w następnym dniu roboczym, ale nie jestem pewien, czy to zadziała, ponieważ niektóre polecenia mogą nie istnieć w przyciętych systemach linuksowych telewizora, takich jak „sed”, więc nadal chcę używać polecenia „znajdź” , „grep” i tak dalej, aby go rozwiązać.
binghenzq

@binghenzq - Dodałem przykłady, które bezpośrednio edytują plik.
slm

-1 Rzadko głosuję za odrzuceniem, ale w tym przypadku kwestia wydaje się być prostszą metodą niż inną bardziej / równie złożoną i prawdopodobnie również zależną. Jeśli pytanie dotyczyło tylko alternatyw dla pełnej instalacji * nix, prawdopodobnie dałbym +1 w przeciwnym razie dobrą odpowiedź.
Michael Durrant

@MichaelDurrant - Właśnie dodałem te skomplikowane edycje wbudowane b / c, o które poprosił OP. Również OP określił wymóg NIE używania sednie I. Sed jest odpowiednim narzędziem do robienia takich zmian, a on oczywiście prosi o lepsze zrozumienie ról tych narzędzi, więc pokazanie komuś tych rzeczy, choć złe, jest bardzo wykształceniem w pokazywaniu im dlaczego. Zbyt wiele razy ppl w wiedzy po prostu powiedz „nie rób tego” bez wyjaśnienia dlaczego, więc jestem. Ale dzięki za zostawienie komentarza, dlaczego DV.
slm

Jasne, myślałem, że to świetna odpowiedź pod każdym innym względem. tak, nienawidzę -1 bez wyjaśnienia.
Michael Durrant

13

Klasyczną alternatywą dla zastępowania pojedynczych liter jest trpolecenie, które powinno być dostępne w prawie każdym systemie:

$ echo "foobar" | tr a b   
foobbr

trjest lepiej niż sedna to faktycznie od użyciem sed(nie wspominając perllub awk) zmiana jednej litery za to jak za pomocą młotka sanki zabić muchę.

grep nie jest do tego przeznaczony, nie modyfikuje danych wejściowych, tylko je przeszukuje.

Alternatywnie możesz skorzystać z możliwości zastępowania niektórych powłok. Tutaj za pomocą ksh, zshlub bashskładnia:

$ foo="foobar"
$ echo "${foo//a/b}"
foobbr

Możemy udzielić bardziej szczegółowych odpowiedzi, jeśli dokładnie wyjaśnisz, jaki problem próbujesz rozwiązać.


Czy istnieje opcja zignorowania wielkości liter ${foo//a/b}?
AlikElzin-kilaka

@ AlikElzin-kilaka Obawiam się, że nie. Będziesz musiał użyć czegoś bardziej wyrafinowane jak na przykład: echo "$foo" | sed 's/a/b/ialbo dać klasę postaci: echo ${foo//[aA]/b}.
terdon

4

Możesz używać Vima w trybie Ex:

ex -s -c '%s/a/b/g|x' file
  1. % wybierz wszystkie linie

  2. s zastąpić

  3. g globalne zastąpienie

  4. x Zapisz i zamknij


wielkie dzięki. żeby dodać, flaga -c służy do wykonania polecenia na początku edycji (ponieważ ex jest edytorem), a flaga -s to albo tryb skryptu wyłączający sprzężenie zwrotne, albo, jak niektórzy lubią mówić, tryb slient. więcej informacji: ex-vi.sourceforge.net/ex.html
Jimmy MG Lim

3

Jeśli pracujesz z plikiem zamiast ze strumieniem, możesz użyć standardowego edytora tekstu ed:

printf '%s\n' ',s/a/b/g' w q | ed file.txt

To powinno być dostępne na każdym * nix. Przecinek ',s/a/b/g'mówi, edaby działał na każdej linii (możesz także użyć %, który będzie bardziej znany, jeśli jesteś przyzwyczajony do vim), a reszta to standardowe wyszukiwanie i zamiana. wkaże mu zapisać (zapisać) plik, qkaże wyjść.

Zauważ, że w przeciwieństwie do -iopcji sed (i podobnych opcji w innych narzędziach), to faktycznie edytuje plik w miejscu zamiast oszukiwać w plikach tymczasowych.

Nie sądzę, żeby można było pracować z streamami, ale tak naprawdę nie wiem zbyt wiele edi nie byłbym zaskoczony, gdyby rzeczywiście miał taką możliwość (filozofia unix jest tym, czym jest).


2

Za pomocą polecenia przodka (w którym -soznacza cichy (cichy) i przecinek przed poleceniami oznacza wykonanie we wszystkich wierszach):

Po prostu drukuję na STDOUT :

ed -s file <<!
,s/a/b/g
,p
q
!

zastępując na miejscu:

ed -s file <<!
,s/a/b/g
w
q
!
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.