No hay forma de hacerlo usando solo sed. Deberá usar al menos la utilidad de búsqueda juntos:
find . -type f -exec sed -i.bak "s/foo/bar/g" {} \;
Este comando creará un .bak
archivo por cada archivo modificado.
Notas:
- El
-i
argumento parased
El comando es una extensión GNU, por lo tanto, si está ejecutando este comando con elsed
de BSD deberá redirigir la salida a un nuevo archivo y luego cambiarle el nombre. - El
find
la utilidad no implementa el-exec
argumento en los antiguos cuadros de UNIX, por lo que deberá usar un| xargs
en su lugar.
Prefiero usar find | xargs cmd
sobre find -exec
porque es más fácil de recordar.
Este ejemplo reemplaza globalmente "foo" con "bar" en archivos .txt en o debajo de su directorio actual:
find . -type f -name "*.txt" -print0 | xargs -0 sed -i "s/foo/bar/g"
El -print0
y -0
las opciones se pueden omitir si sus nombres de archivo no contienen caracteres divertidos como espacios.
Para la portabilidad, no confío en las funciones de sed que son específicas de Linux o BSD. En su lugar, uso el overwrite
guión del libro de Kernighan y Pike sobre el entorno de programación Unix.
El comando es entonces
find /the/folder -type f -exec overwrite '{}' sed 's/old/new/g' {} ';'
Y el overwrite
script (que uso en todas partes) es
#!/bin/sh
# overwrite: copy standard input to output after EOF
# (final version)
# set -x
case $# in
0|1) echo 'Usage: overwrite file cmd [args]' 1>&2; exit 2
esac
file=$1; shift
new=/tmp/$$.new; old=/tmp/$$.old
trap 'rm -f $new; exit 1' 1 2 15 # clean up files
if "[email protected]" >$new # collect input
then
cp $file $old # save original file
trap 'trap "" 1 2 15; cp $old $file # ignore signals
rm -f $new $old; exit 1' 1 2 15 # during restore
cp $new $file
else
echo "overwrite: $1 failed, $file unchanged" 1>&2
exit 1
fi
rm -f $new $old
La idea es que sobrescribe un archivo solo si un comando tiene éxito. Útil en find
y también donde no querrías usar
sed 's/old/new/g' file > file # THIS CODE DOES NOT WORK
porque el shell trunca el archivo antes de sed
puede leerlo.