Następujące polecenie poprawnie zmienia zawartość 2 plików.
sed -i 's/abc/xyz/g' xaa1 xab1
Ale muszę dynamicznie zmieniać kilka takich plików i nie znam ich nazw. Chcę napisać polecenie, które odczyta wszystkie pliki z bieżącego katalogu, zaczynając od xa*
i sed
powinno zmienić zawartość pliku.
sed -i 's/abc/xyz/g' xa*
?Odpowiedzi:
Jeszcze lepiej:
ponieważ nikt nie wie, ile jest plików i łatwo jest przekroczyć limity wiersza poleceń.
Oto, co dzieje się, gdy jest zbyt wiele plików:
źródło
for
poleceniu. Aby się przed tym zabezpieczyć, musisz użyćfind ... | xargs ...
for
niż dlaecho
lubgrep
?"$i"
zamiast,$i
aby uniknąć podziału słów na nazwy plików ze spacjami. W przeciwnym razie jest to bardzo miłe.for
jest ona częścią składni języka, a nie tylko wbudowanym. Ponieważsed -i 's/old/new' *
rozszerzenie*
ALL musi zostać przekazane jako arglista do sed, i jestem całkiem pewien, że musi się to zdarzyć, zanimsed
proces będzie mógł zostać rozpoczęty. Za pomocąfor
pętli pełny arglista (rozszerzenie*
) nigdy nie jest przekazywany jako polecenie, tylko przechowywany w pamięci powłoki i iterowany. W ogóle nie mam na to odniesienia, wydaje się prawdopodobne, że taka jest różnica. (Chciałbym usłyszeć od kogoś bardziej kompetentnego ...)Dziwię się, że nikt nie wspomniał o argumencie -exec do znalezienia, który jest przeznaczony dla tego typu przypadku użycia, chociaż uruchomi on proces dla każdej pasującej nazwy pliku:
Alternatywnie można użyć xargs, który wywoła mniej procesów:
Lub, po prostu, użyj
+
wariantu exec zamiast;
w find, aby umożliwić findowi udostępnienie więcej niż jednego pliku na wywołanie podprocesu:źródło
find ./ -type f -name 'xa*' -exec sed -i '' 's/asd/dsg/g' {} \;
to jest lokalizacja polecenia find./
i para pojedynczych cudzysłowów-i
dla OSX../
jest równe.
i-i
ma tylko parametr backupsuffix.-exec
Opcja znalezisku wraz ze{} +
wystarczy, aby rozwiązać problem, jak wspomniano, i powinno być w porządku dla większości wymagań. Alexargs
ogólnie jest to lepszy wybór, ponieważ umożliwia również równoległe przetwarzanie z tą-p
opcją. Gdy globalna ekspansja jest wystarczająco duża, aby przepełnić długość linii poleceń, prawdopodobnie odniesiesz również korzyść z przyspieszenia w sekwencyjnym przebiegu.Możesz użyć grep i sed razem. To pozwala przeszukiwać podkatalogi rekurencyjnie.
źródło
grep -v
aby uniknąć folderów gitgrep -rl <old> . | grep -v \.git | xargs sed -i 's/<old>/<new>/g'
Te polecenia nie będą działać domyślnie
sed
w systemie Mac OS X.Od
man 1 sed
:Wypróbowany
i
Oba działają dobrze.
źródło
@PaulR opublikował to jako komentarz, ale ludzie powinni postrzegać to jako odpowiedź (i ta odpowiedź najlepiej pasuje do moich potrzeb):
Będzie to działać dla umiarkowanej liczby plików, prawdopodobnie rzędu dziesiątek, ale prawdopodobnie nie rzędu milionów .
źródło
sed -i 's|auth-user-pass nordvpn.txt|auth-user-pass /etc/openvpn/nordvpn.txt|g' *.ovpn
.Innym bardziej wszechstronnym sposobem jest użycie
find
:źródło
Używam
find
do podobnego zadania. Jest to dość proste: musisz podać to jako argument zased
tym:sed -i 's/EXPRESSION/REPLACEMENT/g' `find -name "FILE.REGEX"`
W ten sposób nie musisz pisać skomplikowanych pętli i łatwo jest sprawdzić, które pliki zamierzasz zmienić, po prostu uruchom
find
przed uruchomieniemsed
.źródło
możesz zrobić
Wyszukaj tekst „ xxxx ” i zastąpisz go tekstem „ rrrr ”
źródło
Jeśli możesz uruchomić skrypt, oto co zrobiłem dla podobnej sytuacji:
Używając słownika / hashMap (tablicy asocjacyjnej) i zmiennych dla
sed
polecenia, możemy zapętlać tablicę, zastępując kilka ciągów. Umieszczenie symbolu wieloznacznego wname_pattern
pliku pozwoli zastąpić w miejscu pliki wzorkiem (może to być coś podobnegoname_pattern='File*.txt'
) w określonym katalogu (source_dir
). Wszystkie zmiany są zapisane wlogfile
wdestin_dir
Najpierw deklarowana jest tablica par, każda para jest ciągiem zastępującym, a następnie
WHAT1
zostanie zastąpionaFOR1
iOTHER_string_to replace
zostanie zastąpionastring replaced
w plikuFile.txt
. W pętli tablica jest odczytywana, pierwszy element z pary jest pobierany jako,replace_what=$i
a drugi jakoreplace_for=$j
. Thefind
wyszukiwania poleceń w katalogu nazwa pliku (które mogą zawierać symbol wieloznaczny) ised -i
zastępuje polecenie w jaki został wcześniej zdefiniowany tego samego pliku (ów). W końcu dodałemgrep
przekierowanie do pliku dziennika, aby zarejestrować zmiany dokonane w pliku (plikach).To działało dla mnie
GNU Bash 4.3
sed 4.2.2
i oparte na odpowiedzi VasyiNovikov dla Loop na krotki w bash .źródło