2013-03-14 23 views
147

Potrzebuję rekursywnie wyszukać określony ciąg we wszystkich plikach i podkatalogach w katalogu i zastąpić ten ciąg innym ciągiem.Jak grep i zastąpić

wiem, że polecenie, aby znaleźć to może wyglądać następująco:

grep 'string_to_find' -r ./* 

Ale jak mogę zastąpić każde wystąpienie string_to_find z innym ciągiem?

+0

Nie wierzę, że grep może to zrobić (mógłbym się mylić). Łatwiejszym sposobem byłoby użycie sed lub perl do zastąpienia. –

+1

Spróbuj użyć podciągu 'sed -i '/ /. */Replace /'' –

+1

@Eddy_Em To zastąpi całą linię przez zamianę. Musisz użyć grupowania, aby przechwycić część linii przed i po podłańcuchu, a następnie umieścić ją w linii zastępczej. 'sed -i 's/\ (. * \) substring \ (. * \)/\ 1replace \ 2 /'' – JStrahl

Odpowiedz

1

Zwykle nie z grep, ale raczej z sed -i 's/string_to_find/another_string/g' lub perl -i.bak -pe 's/string_to_find/another_string/g'.

102

Dostałem odpowiedź.

grep -rl matchstring somedir/ | xargs sed -i 's/string1/string2/g' 
+11

To skanowałoby pasujące pliki dwukrotnie ... raz z 'grep', a następnie ponownie z' sed '. Używanie metody "find" jest bardziej wydajne, ale ta metoda, o której wspomniałeś, działa. – cmevoli

+24

W OS X będziesz musiał zmienić 'sed -i 's/str1/str2/g'' na' sed -i ""' s/str1/str2/g'', aby to działało. – jdf

+2

@jdf dlaczego tak jest? – chishaku

158

Inną opcją jest użycie find, a następnie przekazanie go przez sed.

find /path/to/files -type f -exec sed -i 's/oldstring/new string/g' {} \; 
+24

W terminalu OS X 10.10 wymagany jest poprawny ciąg do parametru '-i'. Na przykład 'find/path/to/files -type f -exec sed -i" "" s/oldstring/new string/g "{} \;' W każdym razie podanie pustego łańcucha nadal tworzy plik kopii zapasowej inaczej niż opisano w instrukcji ... – Eonil

+5

Dlaczego otrzymuję komunikat "sed: RE error: illegal byte sequence". I tak, dodałem '-i" "' dla OS X. Działa inaczej. – taco

+0

Mam problem z nielegalną sekwencją bajtów na MacOS 10.12, a to pytanie/odpowiedź rozwiązało mój problem: http://stackoverflow.com/questions/19242275/re-error-illegal-byte-sequence-on-mac-os-x . – abeboparebop

25

Działa to dla mnie najlepsza na OS X:

grep -r -l 'searchtext' . | sort | uniq | xargs perl -e "s/matchtext/replacetext/" -pi 

Źródło: http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files

+0

to jest idealne! działa również z ag: 'ag" search "-l -r. | sortuj uniq | xargs perl -e 's/search/replace' -pi' –

+1

'sort -u' może zastąpić' sort | uniq' –

+0

@sebastiankeller Twoje polecenie Perla nie ma końcowego slasha, który jest błędem składni. – tripleee

0

Innym rozwiązaniem byłoby po prostu użyć Perl z globstar.

Włączenie shopt -s globstar w twoim .bashrc (lub gdziekolwiek) pozwala wzorowi glob ** na rekurencyjne dopasowanie wszystkich podkatalogów i plików.

Zatem stosując perl -pXe 's/SEARCH/REPLACE/g' -i ** będzie rekurencyjnie zastąpić SEARCH z REPLACE.

Flaga mówi perlowi, aby "wyłączyć wszystkie ostrzeżenia" - co oznacza, że ​​nie będzie narzekać na katalogi.

globstar pozwala także robić rzeczy jak sed -i 's/SEARCH/REPLACE/g' **/*.ext jeśli chciał zastąpić SEARCH z REPLACE we wszystkich plikach z rozszerzeniem dzieci .ext.

+0

* "Inną opcją byłoby po prostu użycie perla z globstar ..." * - Nie na urządzeniach Posixy, takich jak Solaris. Właśnie dlatego szczególnie szukam "grep" i "sed". – jww

19

Można nawet śledzić tak ..

Przykład

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g' 

Będzie to szukać napisu „okien” we wszystkich plikach w stosunku do bieżącego katalogu i zastąpić 'okna "z" linux "dla każdego wystąpienia ciągu znaków w każdym pliku.

+2

'grep' jest użyteczny tylko wtedy, gdy istnieją pliki, które nie powinny być modyfikowane.Uruchamianie 'sed' na wszystkich plikach aktualizuje datę modyfikacji pliku, ale pozostawia zawartość niezmienioną, jeśli nie ma dopasowań. – tripleee

+0

@tripleee: Bądź ostrożny z * ... ale [sed] pozostaw zawartość bez zmian, jeśli nie ma żadnych dopasowań "*. Używając" -i ", uważam, że' sed' zmienia czas pliku każdego pliku, który dotyka, nawet chociaż zawartość jest niezmieniona, 'sed' także konwertuje zakończenia linii.Nie używam' sed' w Windows w repozytorium Git, ponieważ wszystkie 'CRLF' są zamienione na' LF'. – jww

3

Inne rozwiązania łączą składni regex. Aby korzystać z Perl/wzory pcre dla zarówno wyszukiwania i zamiany, a unikać przetwarzania każdy plik, to działa całkiem dobrze:

grep -rlZP 'match1' | xargs -0r perl -pi -e 's/match2/replace/g;' 

gdzie match1 i match2 są zwykle identyczne, ale match1 mogą zostać uproszczone w celu usunięcia bardziej zaawansowane funkcje, które są istotne tylko dla substytucji, np przechwytywanie grup.

Tłumaczenie: grep rekurencyjnie i wylistuj pasujące pliki, oddzielone przez nul, aby zabezpieczyć znaki specjalne w nazwie pliku, które pasują do tego wzorca PCRE, a następnie przeprowadź te nazwy plików do xargs, który oczekuje listy rozdzielonej null, ale nie będzie zrób cokolwiek, jeśli nie otrzymasz żadnych nazw, i uzyskaj perla, aby przepisał każdy plik, zastępując linie, w których znalezione są dopasowania.

Dodaj opcję I do grep, aby również zignorować pliki binarne.

+0

Sam Perl jest całkiem zdolny do rekursowania pliku W rzeczywistości istnieje narzędzie ['find2perl'] (https://perldoc.perl.org/5.8.8/find2perl.html), które jest dostarczane z Perlem, które robi tego rodzaju rzeczy bez oszustwa' xargs'. – tripleee

+0

@tripleee 'find' nie wyszukuje zawartości pliku, a celem jest przetwarzanie tylko pasujących plików bez pisania programu Perl. – Walf

-3

znaleźć & zastąpić w vi trybie pliku Składnia jest następująca: :% s/słowo do znalezienia-TU/Replace-Słowo-tu/g

LUB :% s/FindMe/ReplaceME/g

Przykłady

komenda substytutem może być używany zgodnie z własnymi wymaganiami.