Oto moje polecenie (celowe przerwanie):

grep FOO "/Users/gjtorikian/blah" -l | xargs sed -i "" "/FOO/{s/FOO/BAR/g; w /dev/stdout }" 

Na szczycie -level: grep dla FOO w katalogu blah; potokuj tylko nazwę pliku (ponieważ -l) do sed; sed wykonuje bezpośrednie zastąpienie (-i "") i drukuje tylko zmieniony termin na /dev/stdout.

Gdybym miał pominąć -l i pipe, otrzymuję to z grep:

/Users/gjtorikian/blah/baz.cs:1:FOO /Users/gjtorikian/blah/bar.js:1:FOO 

Chcę to sed, aby wykonać zamianę w tekście, a następnie pokaż mi plik i zastąpiony termin, na przykład:

/Users/gjtorikian/blah/baz.cs:1:BAR /Users/gjtorikian/blah/bar.js:1:BAR 

Czy to możliwe? Jeśli ma to znaczenie, wolałbym zachować tylko grep / sed. Czy muszę zrobić drugą grep po ?

Komentarze

  • Nie ' nie widzę sposobu pobierz aktualną nazwę pliku w sed, więc prawdopodobnie będziesz potrzebować drugiego grepa.
  • Poza tym ' nie potrzebujesz '', że ' jest wartością domyślną.
  • W systemie OS X '' nie jest wartością domyślną .

Odpowiedź

Jedną z możliwości byłoby przekazanie wyniku grep do oddzielnego filtra sed.

 grep -l FOO "/Users/gjtorikian/blah/"* | { tee /dev/fd/3 | xargs sed -i -e "/FOO/{" -e "s/FOO/BAR/g" -e "w /dev/stdout" } 3>&1 | sed "s/:FOO$/:BAR/"  

Możesz sed wydrukować numer linii (za pomocą polecenia =), gdy znajdzie dopasowanie i zrobić dalej postprocessing.

Prawdopodobnie byłoby jaśniejsze użycie awk.

 for x in "/Users/gjtorikian/blah/"*; do awk " sub(/FOO/, "BAR") {found=1; print FILENAME ":" NR ":" "BAR" >"/dev/stderr"} 1 {print} END {exit(!found)} " "$x" >"$x.tmp" && mv "$x.tmp" "$x" done  

Odpowiedź

Jak ja „mn ot rodzimym użytkownikiem języka angielskiego, prawdopodobnie nie rozumiem.

Aby „grep” katalog był potrzebny „-r”. Użycie „-l” wypisuje samą nazwę pliku i zatrzymuje grepowanie po pierwszym wystąpieniu.

# pattern=/home ; grep -l "$pattern" /etc/[a-z]* 2>/dev/null | while read line ; do echo "$line:$pattern" ; done /etc/adduser.conf:/home /etc/fstab:/home /etc/fstab~:/home /etc/libuser.conf:/home /etc/mpd.conf:/home /etc/mpd.conf~:/home /etc/mtab:/home /etc/netscsid.conf:/home /etc/passwd:/home /etc/passwd-:/home /etc/sudoers:/home /etc/sudoers.tmp~:/home 

Odpowiedź

Myślę, że” zbytnio komplikujesz problem, próbując zrobić to za jednym zamachem. Możesz po prostu wykonać

grep -H -n /Users/gjtorikian/blah | sed "s/\(^.*?:[0-9]+?:\).*FOO.*/\1BAZ/" 

pobierz listę plików z numerami wierszy i zamiennikami (powinno to działać, o ile nazwy plików nie zawierają dwukropków, ale to i tak jest złym pomysłem w systemie Mac OS …). Następnie możesz wydać

sed -i "" "s/FOO/BAR/g" /Users/gjtorikian/blah 

Nie potrzeba tutaj grep i xarg (możesz jednak wykonać polecenie „find … | xarg”, jeśli masz dużo plików). Jeśli martwisz się, jeśli chodzi o duplikaty, możesz umieścić te dwie linie w skrypcie lub funkcji i tam podstawić zmienne.

Komentarze

  • sed -i ... zmienia czasy plików, nawet jeśli strumień jest niezmieniony.
  • @jww: you ' dobrze, że ' s, ponieważ to edytor strumieniowy, a nie edytor plików, więc opcja -i narusza filozofię unix ( mywiki.wooledge .org / BashFAQ / 021 # Using_nonstandard_tools ). Jeśli chcesz tego uniknąć, użyj ex (np. ex -sc '%s/FOO/BAR/ge|x' /Users/gjtorikian/blah).

Odpowiedź

Rekurencyjnie zamień FOO na BAR w bieżącym katalogu (tryb cichy)

grep -rl "FOO" | xargs sed -i "s/FOO/BAR/" 

Odpowiedź

Jedna linijka

grep -n FOO * -R|awk -F\: "{ print $1 }"|sort|uniq|while read file; do sed -i "s/FOO/BAR/g" $file; done 

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *