Próbuję wyszukać i zamienić ciąg we wszystkich plikach dopasowanych przez grep:
grep -n 'foo' * da mi wynik w postaci:
[filename]:[line number]:[text]
Dla każdego pliku zwróconego przez grep chciałbym zmodyfikować plik, zastępując foogo bar.
Próbuję wyszukać i zamienić ciąg we wszystkich plikach dopasowanych przez grep:
grep -n 'foo' * da mi wynik w postaci:
[filename]:[line number]:[text]
Dla każdego pliku zwróconego przez grep chciałbym zmodyfikować plik, zastępując foogo bar.
Odpowiedzi:
Czy masz na myśli wyszukiwanie i zamianę ciągu we wszystkich plikach dopasowanych przez grep?
perl -p -i -e 's/oldstring/newstring/g' `grep -ril searchpattern *`
Edytować
Ponieważ wydaje się to dość popularne pytanie, pomyślałem, że zaktualizuję.
Obecnie najczęściej używam, ack-grepponieważ jest bardziej przyjazny dla użytkownika. Więc powyższe polecenie brzmiałoby:
perl -p -i -e 's/old/new/g' `ack -l searchpattern`
Aby obsłużyć białe znaki w nazwach plików, możesz uruchomić:
ack --print0 -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'
możesz zrobić więcej ack-grep. Załóżmy, że chcesz ograniczyć wyszukiwanie tylko do plików HTML:
ack --print0 --html -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'
A jeśli biała przestrzeń nie jest problemem, jest jeszcze krótsza:
perl -p -i -e 's/old/new/g' `ack -l --html searchpattern`
perl -p -i -e 's/old/new/g' `ack -f --html` # will match all html files
Wygląda na to, że chcesz, na podstawie podanego przykładu:
sed -i 's/foo/bar/g' *
Nie jest rekursywny (nie schodzi do podkatalogów). Aby uzyskać fajne rozwiązanie zastępując wybrane pliki w całym drzewie, użyłbym find:
find . -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;
Jest *.htmlto wyrażenie, które musi pasować do plików, a .bakpo wykonaniu -ikopii oryginalnego pliku z rozszerzeniem .bak (może to być dowolne rozszerzenie), a gna końcu wyrażenia sed nakazuje sedowi zamianę wielu kopii jedna linia (a nie tylko pierwsza). Funkcja -printznajdowania to wygoda pokazania, które pliki zostały dopasowane. Wszystko to zależy od dokładnych wersji tych narzędzi w twoim systemie.
findkomendę katalog, od którego ma zacząć, na przykład find . -name '*.html'lub find directoryname/ -name '*'.
sed -ie 's/foo/bar/g' *
Jeśli urządzenie sed(1)posiada -iopcję, a następnie używać go w ten sposób:
for i in *; do
sed -i 's/foo/bar/' $i
done
Jeśli nie, istnieje kilka sposobów na różne warianty następujących elementów, w zależności od tego, w jakim języku chcesz grać:
ruby -i.bak -pe 'sub(%r{foo}, 'bar')' *
perl -pi.bak -e 's/foo/bar/' *
for i in *; do ...jest zbędne, sed może przyjąć listę plików jako argumenty.
for i in *; do; sed -i 's/foo/bar/g' "$i"; done
Podobało mi się i korzystałem z powyższego rozwiązania lub przeszukiwania całego systemu i zastępowania wśród tysięcy plików:
find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;
Zakładam z „* .htm?” zamiast .html wyszukuje i znajduje zarówno pliki .htm, jak i .html.
Zastąpiłem .bak bardziej używaną w systemie tyldą (~), aby ułatwić czyszczenie plików kopii zapasowych.
Działa to przy użyciu grepa bez konieczności używania perla lub find.
grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
-iże nie działa dla innych systemów operacyjnych. Działa dla mnie na ubuntu.
xargspodręcznika (w systemie Ubuntu) jest napisane, że -ijest to przestarzałe i do użycia -Izamiast tego. Tak więc powinniśmy powiedzieć:grep -rli 'old-word' * | xargs -I filepath sed -i 's/old-word/new-word/g' filepath
find . -type f -print0 | xargs -0 <sed/perl/ruby cmd>będzie przetwarzać nazwy plików w wielu przestrzeniach jednocześnie, ładując po jednym tłumaczu na wsad. O wiele szybciej.
Odpowiedź już udzielona na temat używania funkcji find i sed
find -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;
to prawdopodobnie standardowa odpowiedź. Lub możesz użyć perl -pi -e s/foo/bar/g'zamiast sedpolecenia.
W przypadku większości szybkich zastosowań może się okazać, że polecenie rpl jest łatwiejsze do zapamiętania. Oto zamiana (foo -> bar), rekurencyjnie dla wszystkich plików w bieżącym katalogu:
rpl -R foo bar .
Nie jest domyślnie dostępny w większości dystrybucji Linuksa, ale można go szybko zainstalować ( apt-get install rpllub podobnie).
Jednak w przypadku trudniejszych zadań, które obejmują wyrażenia regularne i podstawianie z powrotem lub zmianę nazw plików, a także wyszukiwanie i zastępowanie, najbardziej ogólnym i potężnym narzędziem, o którym wiem, jest repren , mały skrypt w Pythonie, który napisałem jakiś czas temu bardziej skomplikowane zadania związane ze zmianą nazw i refaktoryzacją. Powody, dla których możesz to preferować, to:
Przykłady można znaleźć w pliku README .
W rzeczywistości jest to łatwiejsze niż się wydaje.
grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %";
Bułka z masłem. Jeśli dobrze zrozumiesz find, grep, xargs, sed i awk, prawie nic nie jest niemożliwe, jeśli chodzi o manipulowanie plikami tekstowymi w bash :)
Can't open Untitled: No such file or directory, <> line 5podczas próby „Untitled Folder / file.txt”.