Ecco il mio comando (interruzione intenzionale):

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

Al massimo -level: grep per FOO nella directory blah; pipe solo nel nome del file (a causa di -l) a sed; sed esegue una sostituzione in linea (-i "") e stampa solo il termine modificato in /dev/stdout.

Se omettessi -l e pipe, lo ricevo da grep:

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

Quello che voglio è sed per eseguire la sostituzione in linea, quindi mostrami il file e il termine sostituiti; ad esempio:

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

È possibile una cosa del genere? Se è importante, preferirei tenerlo solo con grep / sed. Devo fare un secondo grep dopo ?

Commenti

  • Non ' non vedo un modo per ottieni il nome del file corrente in sed, quindi probabilmente avrai bisogno di un secondo grep.
  • Inoltre, ' non hai bisogno di '', che ' è limpostazione predefinita.
  • Su OS X, '' non è limpostazione predefinita .

Risposta

Una possibilità sarebbe passare loutput di grep a un filtro sed separato.

 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/"  

Potresti fare in modo che sed stampi il numero di riga (con il comando =) quando trova una corrispondenza e procedi oltre postprocessing.

Probabilmente sarebbe più chiaro usare 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  

Risposta

As I “mn ot madrelingua inglese probabilmente non lho capito.

Per “grep” una directory è necessario “-r”. Lutilizzo di “-l” stampa solo il nome del file e interrompe il grepping alla prima occorrenza.

# 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 

Risposta

Penso che tu stia rendendo il problema troppo complicato provando a farlo in una volta sola. Puoi semplicemente fare un

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

a ottenere lelenco dei file con i numeri di riga e le sostituzioni (questo dovrebbe funzionare, a patto che i nomi dei file non contengano i due punti, ma è comunque una cattiva idea in Mac OS …). Successivamente puoi emettere un

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

Non sono necessari grep e xarg qui (puoi fare un “find … | xarg” se hai molti file). Se sei preoccupato per quanto riguarda le duplicazioni, puoi inserire le due righe in uno script o in una funzione e lì eseguire sostituzioni di variabili.

Commenti

  • sed -i ... cambia i tempi dei file anche se lo stream non è cambiato.
  • @jww: tu ' hai ragione, ' s perché è un editor di stream non un editor di file, quindi lopzione -i viola la filosofia unix ( mywiki.wooledge .org / BashFAQ / 021 # Using_nonstandard_tools ). Se vuoi evitarlo, usa ex (ad es. ex -sc '%s/FOO/BAR/ge|x' /Users/gjtorikian/blah).

Risposta

Sostituisci ricorsivamente FOO con BAR nella directory corrente (modalità silenziosa)

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

Risposta

Una riga

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

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *