150 votes

Changer toutes les occurrences dans un dossier

J'ai besoin de faire une recherche regex et un remplacement sur tous les fichiers d'un dossier (et ses sous-dossiers). Quelle serait la commande shell Linux pour faire cela?

Par exemple, je veux exécuter ceci sur tous les fichiers et écraser l'ancien fichier avec le nouveau texte remplacé.

sed 's/texte ancien/nouveau texte/g'

0 votes

212voto

osantana Points 1005

Il n'y a pas de 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 créera un fichier .bak pour chaque fichier modifié.

Remarques:

  • L'argument -i pour la commande sed est une extension GNU, donc, si vous exécutez cette commande avec le sed de BSD, vous devrez rediriger la sortie vers un nouveau fichier puis le renommer.
  • L'utilitaire find n'implémente pas l'argument -exec dans les anciennes boîtes UNIX, donc, vous devrez utiliser un | xargs à la place.

81voto

Dennis Points 5020

Je préfère utiliser find | xargs cmd au lieu de find -exec parce que c'est plus facile à se rappeler.

Cet exemple remplace globalement "foo" par "bar" dans les fichiers .txt à ou en dessous de votre répertoire actuel :

find . -type f -name "*.txt" -print0 | xargs -0 sed -i "s/foo/bar/g"

Les options -print0 et -0 peuvent être omises si vos noms de fichiers ne contiennent pas de caractères spéciaux comme les espaces.

8 votes

Si vous êtes sur OSX, essayez find . -type f -name "*.txt" -print0 | xargs -0 sed -i '' "s/foo/bar/g" (notez que vous fournissez une chaîne vide à l'argument -i).

1 votes

Sur MacOS, exécutez sed -i.bak au lieu de sed -i. Je pense comme mentionné par @JakubKukul, que sed -i '' fonctionne également.

8voto

Norman Ramsey Points 115730

Pour la portabilité, je ne me base pas sur des fonctionnalités de sed 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 ensuite

find /le/dossier -type f -exec overwrite '{}' sed 's/ancien/nouveau/g' {} ';'

Et le script overwrite (que j'utilise partout) est

#!/bin/sh
# overwrite:  copie l'entrée standard en sortie après EOF
# (version finale)

# set -x

case $# in
0|1)        echo 'Utilisation: overwrite fichier cmd [args]' 1>&2; exit 2
esac

fichier=$1; shift
nouveau=/tmp/$$.new; ancien=/tmp/$$.old
trap 'rm -f $nouveau; exit 1' 1 2 15    # nettoyer les fichiers

if "$@" >$nouveau               # collecter l'entrée
then
    cp $fichier $ancien   # sauvegarder le fichier original
    trap 'trap "" 1 2 15; cp $ancien $fichier     # ignorer les signaux
          rm -f $nouveau $ancien; exit 1' 1 2 15   # pendant la restauration
    cp $nouveau $fichier
else
    echo "overwrite: $1 échoué, $fichier inchangé" 1>&2
    exit 1
fi
rm -f $nouveau $ancien

L'idée est de remplacer un fichier uniquement si une commande réussit. Utile dans find et aussi là où vous ne voudriez pas utiliser

sed 's/ancien/nouveau/g' fichier > fichier  # CE CODE NE FONCTIONNE PAS

car le shell tronque le fichier avant que sed puisse le lire.

8voto

Alan Hu Points 51

Exemple : remplacez en ligne {AutoStart} par 1 pour tous les fichiers ini sous le dossier /app/config/ et ses sous-dossiers :

sed -i 's/{AutoStart}/1/g' /app/config/**/*.ini

0 votes

Cela ne le remplace pas, cela imprime simplement le remplacement - si vous voulez le remplacer, ajoutez le drapeau inline : sed -i 's/{AutoStart}/1/g' /app/config/**/*.ini

3voto

paxdiablo Points 341644

Puis-je suggérer (après avoir sauvegardé vos fichiers) :

find /le/dossier -type f -exec sed -ibak 's/ancien/nouveau/g' {} ';'

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X