grep la tubería en sed, reemplazando en línea; pero quiero que sed imprima el nombre de file y la línea cambiada. ¿Es posible?

Aquí está mi command (ruptura intencional):

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

En el nivel superior: grep para FOO en el directory blah ; pipa en solo el nombre del file (debido a -l ) a sed ; sed realiza una sustitución en línea ( -i '' ) e imprime solo el término modificado en /dev/stdout .

Si tuviera que omitir el -l y la tubería, obtengo esto de grep :

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

Lo que quiero es sed para realizar el reemploop en línea, y luego mostrarme el file y el término reemplazado; por ejemplo:

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

¿Es posible tal cosa? Si es importante, preferiría mantenerlo solo con grep / sed . ¿Debo hacer un segundo grep después del sed ?

Una posibilidad sería pasar la salida de grep a un filter de sed separado.

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

Puedes hacer que sed imprima el número de línea (con el command = ) cuando encuentre una coincidencia y hacer un postprocesamiento adicional.

Probablemente sería más claro usar 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 

Como no soy hablante nativo de inglés, probablemente no lo entendí.

Para 'grep' un directory que necesita '-r'. El uso de '-l' imprime solo el nombre del file y detiene el desengrase después de la primera aparición.

 # pattern=/home ; grep -l "$pattern" /etc/[az]* 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 

Creo que estás complicando demasiado el problema tratando de hacerlo de una vez. Usted simplemente puede hacer un

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

para get la list de files con numbers de línea y reemploops (esto debería funcionar, siempre y cuando sus nombres de file no contengan dos puntos, pero eso es una mala idea en Mac OS de todos modos …). Luego puedes emitir un

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

No se necesita grep y xarg aquí (puede hacer un "find … | xarg" si tiene muchos files). Si le preocupan las duplicaciones, puede poner las dos líneas en un script o function y hacer sustituciones de variables allí.