web-dev-qa-db-fra.com

Comment grep et remplacer

Je dois rechercher de manière récursive une chaîne spécifiée dans tous les fichiers et sous-répertoires d'un répertoire et remplacer cette chaîne par une autre chaîne.

Je sais que la commande pour le trouver pourrait ressembler à ceci:

grep 'string_to_find' -r ./*

Mais comment puis-je remplacer chaque instance de string_to_find par une autre chaîne?

215
billtian

Une autre option consiste à utiliser find, puis à le transmettre à sed.

find /path/to/files -type f -exec sed -i 's/oldstring/new string/g' {} \;
216
rezizter

J'ai eu la réponse.

grep -rl matchstring somedir/ | xargs sed -i 's/string1/string2/g'
150
billtian

Vous pouvez même suivre comme ça ..

Exemple

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'

Ceci recherchera la chaîne 'windows' dans tous les fichiers relatifs au répertoire courant et remplacera 'windows' par 'linux' pour chaque occurrence. de la chaîne dans chaque fichier.

34
Dulith De Costa

Cela fonctionne mieux pour moi sur OS X:

grep -r -l 'searchtext' . | sort | uniq | xargs Perl -e "s/matchtext/replacetext/" -pi

Source: http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files

28
Marc Juchli

D'autres solutions combinent les syntaxes regex. Utiliser des modèles Perl/PCRE pour les deux rechercher et remplacer, et éviter de traiter tous les fichiers, cela fonctionne très bien:

grep -rlZP 'match1' | xargs -0r Perl -pi -e 's/match2/replace/g;'

match1 et match2 sont généralement identiques, mais match1 peut être simplifié pour supprimer des fonctionnalités plus avancées ne concernant que la substitution, par ex. capture de groupes.

Traduction: grep récursivement et liste les fichiers correspondants, séparés par un zéro pour protéger tous les caractères spéciaux du nom de fichier, qui correspondent à ce modèle PCRE, puis dirigent ces noms de fichiers vers xargs qui attend une liste séparée par des zéros, mais ne fera rien si aucun les noms sont reçus et Perl doit réécrire chaque fichier en remplaçant les lignes où des correspondances sont trouvées.

Ajoutez l'option I à grep pour ignorer également les fichiers binaires.

4
Walf

Généralement pas avec grep, mais plutôt avec sed -i 's/string_to_find/another_string/g' ou Perl -i.bak -pe 's/string_to_find/another_string/g'.

4
minopret

Soyez très prudent lorsque vous utilisez find et sed dans un dépôt Git! Si vous n'excluez pas les fichiers binaires, vous pouvez vous retrouver avec cette erreur:

error: bad index file sha1 signature 
fatal: index file corrupt

Pour résoudre cette erreur, vous devez rétablir la sed en remplaçant votre new_string par votre old_string. Cela inversera les chaînes que vous avez remplacées et vous permettra de revenir au début du problème.

La bonne façon de rechercher une chaîne et de la remplacer est de sauter find et d'utiliser grep à la place afin d'ignorer les fichiers binaires:

sed -ri -e "s/old_string/new_string/g" $(grep -Elr --binary-files=without-match "old_string" "/files_dir")

Crédits pour @hobs

3
tsveti_iko

Voici ce que je ferais:

find /path/to/dir -type f -iname "*filename*" -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'

ceci recherchera tous les fichiers contenant filename dans le nom du fichier sous le /path/to/dir, que pour chaque fichier trouvé, recherchez la ligne avec searchstring et remplacez old par new.

0
tinnick

Une autre option serait simplement d’utiliser Perl avec globstar.

L'activation de shopt -s globstar dans votre .bashrc (ou à tout autre endroit) permet au motif global ** de faire correspondre tous les sous-répertoires et tous les fichiers.

Ainsi, l'utilisation de Perl -pXe 's/SEARCH/REPLACE/g' -i ** remplacera de manière récursive SEARCH par REPLACE.

Le drapeau -X indique à Perl de "désactiver tous les avertissements", ce qui signifie qu'il ne se plaindra pas des répertoires.

Le globstar vous permet également de faire des choses comme sed -i 's/SEARCH/REPLACE/g' **/*.ext si vous voulez remplacer SEARCH par REPLACE dans tous les fichiers enfants portant l'extension .ext.

0
GuiltyDolphin