J'essaie de rechercher et de remplacer une chaîne dans tous les fichiers correspondant à grep sur une machine linux. J'ai quelques morceaux de ce que je veux faire, mais je ne suis pas sûr de la meilleure façon de les enchaîner.
grep -n 'foo' *
me donnera la sortie sous la forme:
[filename]:[line number]:[text]
Pour chaque fichier renvoyé par grep, j'aimerais remplacer "foo" par "bar" et écrire le résultat dans le fichier. Y a-t-il un bon moyen de faire ça? Peut-être un pipeline de fantaisie?
Voulez-vous dire rechercher et remplacer une chaîne dans tous les fichiers correspondant à grep?
Perl -p -i -e 's/oldstring/newstring/g' `grep -ril searchpattern *`
Éditer
Puisque cela semble être une question assez populaire, je pensais que je mettrais à jour.
De nos jours, j'utilise principalement ack-grep
comme c'est plus convivial. Donc, la commande ci-dessus serait:
Perl -p -i -e 's/old/new/g' `ack -l searchpattern`
Pour gérer les espaces dans les noms de fichiers, vous pouvez exécuter:
ack --print0 -l searchpattern | xargs -0 Perl -p -i -e 's/old/new/g'
vous pouvez faire plus avec ack-grep
. Supposons que vous souhaitiez limiter la recherche aux fichiers HTML uniquement:
ack --print0 --html -l searchpattern | xargs -0 Perl -p -i -e 's/old/new/g'
Et si l'espace blanc n'est pas un problème, c'est encore plus court:
Perl -p -i -e 's/old/new/g' `ack -l --html searchpattern`
Perl -p -i -e 's/old/new/g' `ack -f --html` # will match all html files
Cela semble être ce que vous voulez, d'après l'exemple que vous avez donné:
sed -i 's/foo/bar/g' *
Ce n'est pas récursif (il ne descendra pas dans les sous-répertoires). Pour une solution intéressante en remplaçant dans des fichiers sélectionnés tout au long d’un arbre, j’utiliserais:
find . -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;
Le *.html
est l'expression à laquelle doivent correspondre les fichiers, le .bak
après le -i
fait une copie du fichier original, avec une extension .bak (cela peut être n'importe quelle extension) et le g
à la fin de l'expression sed indique à sed de remplacer plusieurs copies sur une ligne (plutôt que seulement le premier). Le -print
trouver est pratique pour montrer quels fichiers ont été mis en correspondance. Tout cela dépend des versions exactes de ces outils sur votre système.
Si votre sed(1)
a un -i
_ option, utilisez-le comme ceci:
for i in *; do
sed -i 's/foo/bar/' $i
done
Sinon, il y a plusieurs façons de varier les options suivantes en fonction de la langue avec laquelle vous voulez jouer:
Ruby -i.bak -pe 'sub(%r{foo}, 'bar')' *
Perl -pi.bak -e 's/foo/bar/' *
J'aime et utilise la solution ci-dessus ou une recherche à l'échelle du système et remplace parmi des milliers de fichiers:
find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;
Je suppose avec le '* .htm?' au lieu de .html, il recherche et trouve les fichiers .htm et .html de la même manière.
Je remplace le .bak par le tilde (~) plus répandu à l’échelle du système pour faciliter le nettoyage des fichiers de sauvegarde.
Cela fonctionne en utilisant grep sans avoir besoin d'utiliser Perl ou find.
grep -rli 'old-Word' * | xargs -i@ sed -i 's/old-Word/new-Word/g' @
find . -type f -print0 | xargs -0 <sed/Perl/Ruby cmd>
traitera simultanément plusieurs noms de fichiers contenant de l’espace, chargeant un interprète par lot. Plus vite.
C'est en fait plus facile qu'il n'y parait.
grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %";
Peasy facile. Si vous maîtrisez parfaitement find, grep, xargs, sed et awk, rien n’est impossible en ce qui concerne la manipulation de fichiers texte en bash :)
La réponse déjà donnée d'utiliser find et sed
find -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;
est probablement la réponse standard. Ou vous pouvez utiliser Perl -pi -e s/foo/bar/g'
À la place de la commande sed
.
Pour les utilisations les plus rapides, vous pouvez trouver que la commande rpl est plus facile à mémoriser. Voici remplacement (foo -> bar), de manière récursive sur tous les fichiers du répertoire en cours:
rpl -R foo bar .
Il n'est pas disponible par défaut sur la plupart des distributions Linux mais son installation est rapide (apt-get install rpl
Ou similaire).
Toutefois, pour les travaux plus difficiles qui impliquent des expressions régulières et des substitutions de dos, ou des renommages de fichiers ainsi que des opérations de recherche et remplacement, l'outil le plus général et le plus puissant dont je dispose est repren , un petit Python que j'ai écrit il y a quelque temps pour certaines tâches de renommage et de refactoring plus épineuses. Les raisons pour lesquelles vous pourriez le préférer sont les suivantes:
Consultez le fichier README pour des exemples.