Używanie sed i grep / egrep do wyszukiwania i zamiany


97

Używam, egrep -Rpo którym następuje wyrażenie regularne zawierające około 10 unii, na przykład: .jpg | .png | .gifitd. To działa dobrze, teraz chciałbym zamienić wszystkie znalezione ciągi na.bmp

Myślałem o czymś takim

egrep -lR "\.jpg|\.png|\.gif" . | sed "s/some_expression/.jpg/" file_it_came_form

więc problem polega na tym, jak zrobić podobne wyrażenie regularne unii w programie sedi jak powiedzieć mu, aby zapisał zmiany w pliku, z którego pobrał dane wejściowe.


2
Znalazłem to pytanie, szukając sposobów wyszukiwania i zastępowania wielu plików w hierarchii katalogów. Dla innych w mojej sytuacji wypróbuj rpl .
— Titaniumdecoy

dziękuję rpl działa i jest naprawdę łatwy do zapamiętania ... po prostu rpl old_string new_string target_files.
— cesarpachon

Odpowiedzi:


183

Użyj tego polecenia:

egrep -lRZ "\.jpg|\.png|\.gif" . \
    | xargs -0 -l sed -i -e 's/\.jpg\|\.gif\|\.png/.bmp/g'
  • egrep: znajdź pasujące wiersze przy użyciu rozszerzonych wyrażeń regularnych

    • -l: wyświetla tylko pasujące nazwy plików

    • -R: przeszukuje rekurencyjnie wszystkie podane katalogi

    • -Z: użyj \0jako separatora rekordów

    • "\.jpg|\.png|\.gif": Pasuje do jednego z ciągów ".jpg", ".gif"lub".png"

    • .: rozpoczęcie wyszukiwania w bieżącym katalogu

  • xargs: wykonuje polecenie ze stdin jako argumentem

    • -0: użyj \0jako separatora rekordów. Jest to ważne, aby dopasować -Zof egrepi uniknąć oszukania przez spacje i znaki nowej linii w nazwach plików wejściowych.

    • -l: użyj jednej linii na polecenie jako parametru

  • sed: The s TREAM wyd itor

    • -i: zamień plik wejściowy na wyjście bez tworzenia kopii zapasowej

    • -e: użyj następującego argumentu jako wyrażenia

    • 's/\.jpg\|\.gif\|\.png/.bmp/g'Zamienić wszystkie wystąpienia ciągów ".jpg", ".gif"lub ".png"z".bmp"


to wszystko działa z wyjątkiem | w części sed. Nie rozumiem jednak dlaczego, skoro to ma sens ... -l część xargs dawała mi błędy, więc je usunąłem, czy to może być powiązane?
— Ori

Odkryłem, że to polecenie dodaje nową linię na końcu wszystkich plików, które przetwarza.
— titaniumdecoy

@titanumdecoy: Nie udało mi się odtworzyć tego zachowania. jakiej wersji seda używasz i na jakim systemie operacyjnym jesteś?
— David Schmitt,

1
@DavidSchmitt: Prawdopodobnie chcesz używać sed -rrozszerzonych wyrażeń regularnych. W tym momencie wzorzec będzie pasował do tego, co jest używane w egrep i możesz chcieć umieścić go w zmiennej do ponownego wykorzystania.
— bukzor

to polecenie zaoszczędziło mi wielu godzin pracy na kopiowaniu plików nagłówkowych z mojej aplikacji do utworzonej przeze mnie biblioteki. To jest niesamowite :) Oto polecenie, którego użyłem egrep -lRZ "\ .h $". | xargs -0 tar -cvf headers.tar | (cp headers.tar headers; cd headers; tar xf headers.tar;)
— The Lazy Coder,

11

Szczerze mówiąc, tak jak uwielbiam seda za odpowiednie zadania, jest to zdecydowanie zadanie dla perla - jest to naprawdę potężniejsze dla tego rodzaju linijków, zwłaszcza, aby "zapisać to skąd pochodzi" ( -iprzełącznik Perla robi to dla you, a opcjonalnie pozwala również zachować starą wersję, np. z dołączonym .bak, po prostu użyj -i.bakzamiast tego).

perl -i.bak -pe 's/\.jpg|\.png|\.gif/.jpg/

zamiast skomplikowanej pracy w sedzie (jeśli tam nawet jest to możliwe) lub awk ...


6
sed używa -i, tak jak perl.
— Stobor

@Stobor - przysięgam, że miałem problemy z operacją perla, kiedy podałem ciąg zastępujący wyrażenie regularne, zrobiło dokładnie to, co chciałem, w przeciwieństwie do seda, nawet jeśli dałem opcję wyrażenia regularnego na sed... Myślę, że albo zapomniałem niektórych flag do seda lub miał ograniczenia.
— meder omuraliev

10

Inny sposób, aby to zrobić

find . -name *.xml -exec sed -i "s/4.6.0-SNAPSHOT/5.0.0-SNAPSHOT/" {} \;

Trochę pomocy odnośnie powyższego polecenia

Znalezisko wykona za Ciebie wyszukiwanie w bieżącym katalogu wskazanym przez .

-name nazwa pliku w moim przypadku pom.xml może zawierać symbole wieloznaczne.

-exec wykonać

sed edytor strumieni

-i ignoruj ​​wielkość liter

s jest zamiennikiem

/4.6.0.../ Ciąg do przeszukania

/5.0.0.../ Sznurek do wymiany


może nie tak potężny - ale jest to dla mnie o wiele łatwiejsze do zrozumienia niż zaakceptowana odpowiedź
— icc97

5

Nie mogłem sprawić, aby żadne z poleceń na tej stronie działało dla mnie: rozwiązanie sed dodało nową linię na końcu wszystkich przetwarzanych plików, a rozwiązanie Perl nie mogło zaakceptować wystarczającej liczby argumentów z find. Znalazłem takie rozwiązanie, które działa idealnie:

find . -type f -name '*.[hm]' -print0 
    | xargs -0 perl -pi -e 's/search_regex/replacement_string/g'

To rekursja dół bieżącej drzewo katalogów i wymienić search_regexz replacement_stringna wszystkie pliki kończące się .hlub.m .

W przeszłości do tego celu używałem również rpl .


0

spróbuj czegoś za pomocą pętli for

 for i in `egrep -lR "YOURSEARCH" .` ; do echo  $i; sed 's/f/k/' <$i >/tmp/`basename $i`; mv /tmp/`basename $i` $i; done

nie ładne, ale powinno.


3
xargs jest tutaj zdecydowanie bardziej odpowiedni.
— Nathan Fellman

1
i użycie |while read iwzorca umożliwiłoby przesyłanie strumieniowe i uniknęło ograniczeń długości, gdy wyniki egrep stałyby się zbyt długie
— David Schmitt

0

Mój przypadek użycia polegał na tym, że chciałem zamienić foo:/Drive_Lettergo na foo:/bar/baz/xyz W moim przypadku udało mi się to zrobić za pomocą następującego kodu. Znajdowałem się w tym samym katalogu, w którym znajdowała się większość plików.

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'

mam nadzieję, że pomogło.

AKTUALIZACJA s | foo: / litera_dysku: | foo: / ba / baz / xyz | g


Możesz użyć innych ograniczników dla polecenia sed, a dzięki temu nazwy ścieżek są znacznie ładniejsze:sed 's|foo:/Drive_letter:|foo:/ba/baz/xyz|g'
— Kevin
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.