Non c'è modo di farlo usando solo sed. Dovrai utilizzare almeno l'utility find insieme:
find . -type f -exec sed -i.bak "s/foo/bar/g" {} \;
Questo comando creerà un .bak file per ogni file modificato.
Note:
- Il
-iargomento persedcommand è un'estensione GNU, quindi, se stai eseguendo questo comando conseddi BSD dovrai reindirizzare l'output a un nuovo file e rinominarlo. - Il
findl'utility non implementa il-execargomento nelle vecchie scatole UNIX, quindi dovrai usare un| xargsinvece.
Preferisco usare find | xargs cmd oltre find -exec perché è più facile da ricordare.
Questo esempio sostituisce globalmente "foo" con "bar" nei file .txt nella directory corrente o al di sotto di essa:
find . -type f -name "*.txt" -print0 | xargs -0 sed -i "s/foo/bar/g"
Il -print0 e -0 le opzioni possono essere tralasciate se i nomi dei file non contengono caratteri strani come gli spazi.
Per la portabilità, non mi affido alle funzionalità di sed specifiche di Linux o BSD. Invece uso il overwrite script dal libro di Kernighan e Pike sull'ambiente di programmazione Unix.
Il comando è quindi
find /the/folder -type f -exec overwrite '{}' sed 's/old/new/g' {} ';'
E il overwrite script (che uso ovunque) è
#!/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 "example@unixlinux.online" >$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
L'idea è che sovrascrive un file solo se un comando ha successo. Utile in find e anche dove non vorresti usare
sed 's/old/new/g' file > file # THIS CODE DOES NOT WORK
perché la shell tronca il file prima di sed può leggerlo.