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?
Une autre option consiste à utiliser find, puis à le transmettre à sed.
find /path/to/files -type f -exec sed -i 's/oldstring/new string/g' {} \;
J'ai eu la réponse.
grep -rl matchstring somedir/ | xargs sed -i 's/string1/string2/g'
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.
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
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;'
où 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.
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'
.
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
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
.
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
.