J'ai besoin de rechercher et de remplacer une expression régulière sur tous les fichiers d'un dossier (et de ses sous-dossiers). Quelle serait la commande Linux shell pour faire cela?
Par exemple, je veux exécuter cela sur tous les fichiers et remplacer l'ancien fichier par le nouveau texte remplacé.
sed 's/old text/new text/g'
Il n'y a aucun moyen de le faire en utilisant uniquement sed. Vous devrez utiliser au moins l'utilitaire find ensemble:
find . -type f -exec sed -i.bak "s/foo/bar/g" {} \;
Cette commande va créer un .bak
fichier pour chaque fichier modifié.
Notes:
-i
l'argument de la commande sed
est une extension GNU, donc, si vous exécutez cette commande avec le sed
du BSD, vous devrez rediriger la sortie vers un nouveau fichier puis renommez-le.find
n'implémente pas le -exec
argument dans les anciennes boîtes UNIX, vous devrez donc utiliser un | xargs
au lieu.Je préfère utiliser find | xargs cmd
plus de find -exec
parce que c'est plus facile à retenir.
Cet exemple remplace globalement "foo" par "bar" dans les fichiers .txt au niveau ou en dessous de votre répertoire actuel:
find . -type f -name "*.txt" -print0 | xargs -0 sed -i "s/foo/bar/g"
Le -print0
et -0
les options peuvent être omises si vos noms de fichiers ne contiennent pas de caractères géniaux tels que des espaces.
Pour la portabilité, je ne me fie pas aux fonctionnalités de sed qui sont spécifiques à Linux ou BSD. À la place, j'utilise le script overwrite
du livre de Kernighan et Pike sur l'environnement de programmation Unix.
La commande est alors
find /the/folder -type f -exec overwrite '{}' sed 's/old/new/g' {} ';'
Et le script overwrite
(que j'utilise partout) est
#!/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 "$@" >$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'idée est qu'il écrase un fichier uniquement si une commande réussit. Utile dans find
et aussi là où vous ne souhaitez pas utiliser
sed 's/old/new/g' file > file # THIS CODE DOES NOT WORK
car le shell tronque le fichier avant que sed
puisse le lire.
Puis-je suggérer (après avoir sauvegardé vos fichiers):
find /the/folder -type f -exec sed -ibak 's/old/new/g' {} ';'