Aici este comanda mea (pauză intenționată):

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

La maxim -nivel: grep pentru FOO în directorul blah; introduceți doar numele fișierului (din cauza -l) la sed; sed efectuează o înlocuire în linie (-i "") și imprimă doar termenul modificat în /dev/stdout.

Dacă ar omite -l și pipe, obțin acest lucru înapoi de la grep:

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

Ce vreau este sed pentru a efectua înlocuirea în linie și apoi arată-mi fișierul și termenul înlocuit; de exemplu:

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

Este posibil așa ceva? Dacă contează, aș prefera să-l păstrez numai cu grep / sed. Trebuie să fac un al doilea grep după ?

Comentarii

  • Nu ' nu văd o modalitate de a obțineți numele fișierului curent în sed, deci probabil veți avea nevoie de un al doilea grep.
  • De asemenea, nu aveți nevoie de ' de '', că ' este valoarea implicită.
  • Pe OS X, '' nu este valoarea implicită .

Răspuns

O posibilitate ar fi să trimiți rezultatul grep la un filtru separat 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/"  

Puteți face sed să imprimați numărul liniei (cu comanda =) atunci când găsește o potrivire și faceți mai departe postprocesare.

Probabil ar fi mai clar să folosiți 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  

Răspuns

As I „mn Vorbitor nativ de engleză, probabil nu l-am obținut.

Pentru a „grep” un director aveți nevoie de „-r”. Utilizarea „-l” tipărește doar numele fișierului și se oprește grepping-ul după prima apariție.

# 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 

Răspuns

Cred că faceți problema prea complicată încercând să o faceți dintr-o singură dată. Pur și simplu puteți face o

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

obțineți lista de fișiere cu numere de linie și înlocuiri (acest lucru ar trebui să funcționeze, atâta timp cât numele fișierelor dvs. nu conțin două puncte, dar „oricum este o idee proastă în Mac OS …). După aceea, puteți emite un

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

Nu este nevoie de grep și xarg aici (puteți face un „find … | xarg” dacă aveți totuși o mulțime de fișiere). Dacă sunteți îngrijorat despre duplicări, puteți pune cele două linii într-un script sau funcție și puteți face substituiri variabile acolo.

Comentarii

  • sed -i ... modifică durata fișierelor chiar dacă fluxul este neschimbat.
  • @jww: ai ' dreptate, că ' s pentru că este un editor de flux, nu un editor de fișiere, deci opțiunea -i încalcă filosofia unix ( mywiki.wooledge .org / BashFAQ / 021 # Using_nonstandard_tools ). Dacă doriți să evitați această utilizare, utilizați ex (de ex., ex -sc '%s/FOO/BAR/ge|x' /Users/gjtorikian/blah).

Răspunde

Înlocuiește recursiv FOO cu BAR în dir curent (mod silențios)

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

Răspuns

O linie

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

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *