J'ai besoin de rechercher récursivement une chaîne spécifiée dans tous les fichiers et sous-répertoires d'un répertoire et de 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?
sed -i 's/.*substring.*/replace/'
sed -i 's/\(.*\)substring\(.*\)/\1replace\2/'
Réponses:
Une autre option consiste à utiliser find puis à le passer par sed.
la source
-i
est requise. Par exemple,find /path/to/files -type f -exec sed -i "" "s/oldstring/new string/g" {} \;
Quoi qu'il en soit, fournir une chaîne vide crée toujours un fichier de sauvegarde contrairement à ce qui est décrit dans le manuel ...-i ""
pour OS X. Cela fonctionne autrement.CRLF
àLF
sous Windows.J'ai eu la réponse.
la source
grep
puis à nouveau avecsed
. L'utilisation de lafind
méthode est plus efficace mais cette méthode que vous mentionnez fonctionne.sed -i 's/str1/str2/g'
àsed -i "" 's/str1/str2/g'
pour que cela fonctionne.grep
parcourt tous les fichiers etsed
ne scanne que les fichiers correspondantsgrep
. Avec lafind
méthode dans l'autre réponse,find
répertorie d'abord tous les fichiers, puissed
analyse tous les fichiers de ce répertoire. Cette méthode n'est donc pas nécessairement plus lente, elle dépend du nombre de correspondances et des différences de vitesse de recherche entresed
,grep
etfind
.Vous pouvez même le faire comme ceci:
Exemple
Cela recherchera la chaîne « windows » dans tous les fichiers relatifs au répertoire actuel et remplacera « windows » par « linux » pour chaque occurrence de la chaîne dans chaque fichier.
la source
grep
n'est utile que s'il existe des fichiers qui ne doivent pas être modifiés. L'exécutionsed
sur tous les fichiers mettra à jour la date de modification du fichier mais laissera le contenu inchangé s'il n'y a pas de correspondance.-i
, je crois quesed
change l'heure du fichier de chaque fichier qu'il touche, même si le contenu est inchangé.sed
convertit également les fins de lignesed
CRLF
LF
Cela fonctionne mieux pour moi sur OS X:
Source: http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files
la source
ag "search" -l -r . | sort | uniq | xargs perl -e 's/search/replace' -pi
sort -u
partie paire de cela? Dans quelles circonstances vous attendriez-vousgrep -rl
à produire deux fois le même nom de fichier?D'autres solutions mélangent des syntaxes regex. Pour utiliser les modèles perl / PCRE à la fois pour la recherche et le remplacement, et pour traiter uniquement les fichiers correspondants, cela fonctionne assez bien:
où
match1
etmatch2
sont généralement identiques maismatch1
peuvent être simplifiés pour supprimer des fonctionnalités plus avancées qui ne concernent que la substitution, par exemple la capture de groupes.Traduction:
grep
récursivement et liste les fichiers qui correspondent à ce modèle PCRE, séparés par nul pour protéger tous les caractères spéciaux dans le nom de fichier, puis dirigez les noms de fichiers versxargs
lesquels attend une liste séparée par nul, mais ne fera rien si aucun nom n'est reçu, et obtenirperl
à remplacer les lignes où les correspondances sont trouvées.Ajoutez le
I
commutateur àgrep
pour ignorer les fichiers binaires. Pour la correspondance sensible à la casse, supprimez lei
commutateur degrep
et l'i
indicateur attaché à l'expression de substitution, mais pas lei
commutateur surperl
lui-même.la source
find2perl
livré avec Perl qui fait ce genre de chose sans aucunexargs
astuce.find
ne recherche pas le contenu des fichiers, et le but est de ne traiter que les fichiers correspondants sans écrire de programme Perl.Généralement pas avec grep, mais plutôt avec
sed -i 's/string_to_find/another_string/g'
ouperl -i.bak -pe 's/string_to_find/another_string/g'
.la source
Soyez très prudent lors de l'utilisation
find
etsed
dans un dépôt git! Si vous n'excluez pas les fichiers binaires, vous pouvez vous retrouver avec cette erreur:Pour résoudre cette erreur, vous devez annuler le
sed
en remplaçant votrenew_string
par votreold_string
. Cela reviendra à vos chaînes remplacées, vous serez donc de retour au début du problème.La bonne façon de rechercher une chaîne et de la remplacer est d'ignorer
find
et d'utiliser à lagrep
place afin d'ignorer les fichiers binaires:Crédits pour @hobs
la source
Voici ce que je ferais:
cela va rechercher tous les fichiers contenant
filename
dans le nom du fichier sous le/path/to/dir
, que pour chaque fichier trouvé, recherchez la ligne avecsearchstring
et remplacezold
parnew
.Cependant, si vous voulez omettre de rechercher un fichier spécifique avec une
filename
chaîne dans le nom du fichier, faites simplement:Cela fera la même chose ci-dessus, mais pour tous les fichiers trouvés sous
/path/to/dir
.la source
Une autre option serait d'utiliser simplement perl avec globstar.
L'activation
shopt -s globstar
dans votre.bashrc
(ou n'importe où) permet au**
modèle glob de correspondre à tous les sous-répertoires et fichiers de manière récursive.Ainsi, l'utilisation
perl -pXe 's/SEARCH/REPLACE/g' -i **
sera récursivement remplacéeSEARCH
parREPLACE
.Le
-X
drapeau 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 vouliez remplacerSEARCH
avecREPLACE
dans tous les fichiers enfants avec l'extension.ext
.la source
grep
etsed
.