Muszę rekurencyjnie wyszukać określony ciąg we wszystkich plikach i podkatalogach w katalogu i zastąpić ten ciąg innym ciągiem.
Wiem, że polecenie znalezienia może wyglądać następująco:
grep 'string_to_find' -r ./*
Ale jak mogę zastąpić każde wystąpienie string_to_find
innym ciągiem?
sed -i 's/.*substring.*/replace/'
sed -i 's/\(.*\)substring\(.*\)/\1replace\2/'
Odpowiedzi:
Inną opcją jest użycie find, a następnie przekazanie go przez sed.
źródło
-i
wymagany jest odpowiedni ciąg rozszerzenia parametru . Na przykład wfind /path/to/files -type f -exec sed -i "" "s/oldstring/new string/g" {} \;
każdym razie podanie pustego ciągu nadal tworzy plik kopii zapasowej, inaczej niż opisano w podręczniku ...-i ""
dla OS X. Działa inaczej.CRLF
naLF
w systemie Windows.Dostałem odpowiedź.
źródło
grep
a następnie ponownie za pomocąsed
. Zastosowaniefind
metody jest bardziej wydajne, ale wspomniana metoda działa.sed -i 's/str1/str2/g'
abysed -i "" 's/str1/str2/g'
to działało.grep
przegląda wszystkie pliki ised
skanuje tylko pliki pasujące dogrep
. Wfind
metodzie z drugiej odpowiedzifind
najpierw wyświetla listę wszystkich plików, a następniesed
skanuje wszystkie pliki w tym katalogu. Ta metoda niekoniecznie jest wolniejsza, zależy to od liczby dopasowań i różnic w prędkości wyszukiwania międzysed
,grep
afind
.Możesz nawet zrobić to w ten sposób:
Przykład
Spowoduje to wyszukanie ciągu „ windows ” we wszystkich plikach względem bieżącego katalogu i zastąpienie „ windows ” ciągiem „ linux ” dla każdego wystąpienia ciągu w każdym pliku.
źródło
grep
to przydatne tylko wtedy, gdy istnieją pliki, których nie należy modyfikować. Uruchomieniesed
na wszystkich plikach zaktualizuje datę modyfikacji pliku, ale pozostawi zawartość bez zmian, jeśli nie ma żadnych dopasowań.-i
, uważam, żesed
zmienia czas pliku każdego dotkniętego pliku, nawet jeśli zawartość jest niezmieniona.sed
również konwertuje zakończenia linii . nie używaćsed
w systemie Windows w repo Git, ponieważ wszystkieCRLF
są zmienianeLF
.Działa to najlepiej dla mnie w systemie OS X:
Źródło: http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files
źródło
ag "search" -l -r . | sort | uniq | xargs perl -e 's/search/replace' -pi
sort -u
nawet jego część? W jakich okolicznościach spodziewałbyśgrep -rl
się, że utworzysz dwukrotnie tę samą nazwę pliku?Inne rozwiązania łączą składnie wyrażeń regularnych. Aby używać wzorców perl / PCRE zarówno do wyszukiwania, jak i zamiany oraz do przetwarzania tylko pasujących plików, działa to całkiem dobrze:
gdzie
match1
imatch2
są zwykle identyczne, alematch1
można je uprościć, aby usunąć bardziej zaawansowane funkcje, które są istotne tylko w przypadku podstawienia, np. przechwytywanie grup.Tłumaczenie:
grep
rekurencyjnie i wyświetl listę plików pasujących do tego wzorca PCRE, oddzielonych nul, aby chronić znaki specjalne w nazwie pliku, a następnie potokuj nazwy plików, doxargs
których oczekuje listy rozdzielonej nul, ale nic nie zrobi, jeśli nie otrzyma żadnych nazw, i przejdźperl
do linii zastępczych, w których znaleziono dopasowania.Dodaj
I
przełącznik,grep
aby zignorować pliki binarne. Dla przypadku wrażliwych dopasowywania spadeki
przechodzenia zgrep
, ii
flagę dołączony do ekspresji podstawienia, ale niei
przełącznika naperl
siebie.źródło
find2perl
dostarczane z Perlem, które robi takie rzeczy bez żadnychxargs
sztuczek.find
nie wyszukuje zawartości pliku, a chodzi o to, aby przetwarzać tylko pasujące pliki bez pisania programu w Perlu.Zwykle nie z grep, ale raczej z
sed -i 's/string_to_find/another_string/g'
lubperl -i.bak -pe 's/string_to_find/another_string/g'
.źródło
Zachowaj ostrożność podczas używania
find
ised
w repo git! Jeśli nie wykluczysz plików binarnych, możesz skończyć z tym błędem:Aby rozwiązać ten błąd, musisz przywrócić
sed
, zastępującnew_string
swójold_string
. Spowoduje to przywrócenie zastąpionych ciągów, dzięki czemu wrócisz do początku problemu.Prawidłowym sposobem wyszukiwania ciągu i zastępowania go jest pominięcie
find
i użyciegrep
w celu zignorowania plików binarnych:Kredyty dla @hobs
źródło
Oto co bym zrobił:
to będzie szukać wszystkich plików zawierających
filename
w nazwie pliku, pod/path/to/dir
, niż dla każdego pliku znaleźć, szukaj linii zsearchstring
i wymienićold
znew
.Chociaż jeśli chcesz pominąć wyszukiwanie określonego pliku z
filename
ciągiem w nazwie pliku, po prostu wykonaj następujące czynności:To zrobi to samo powyżej, ale do wszystkich plików znajdujących się pod
/path/to/dir
.źródło
Inną opcją byłoby po prostu użycie perla z globstar.
Włączenie
shopt -s globstar
w.bashrc
(lub gdziekolwiek) pozwala**
wzorzec globu dopasowywał rekursywnie wszystkie podkatalogi i pliki.Zatem stosując
perl -pXe 's/SEARCH/REPLACE/g' -i **
rekurencyjnie zastąpićSEARCH
zREPLACE
.-X
Flaga mówi Perl „Wyłącz wszystkie ostrzeżenia” - co oznacza, że nie będą narzekać katalogów.Globstar pozwala również robić rzeczy, jak
sed -i 's/SEARCH/REPLACE/g' **/*.ext
gdybyś chciał wymienićSEARCH
sięREPLACE
we wszystkich plikach z rozszerzeniem dzieci.ext
.źródło
grep
ised
.