En utilisant un shell comme bash ou zshell, comment puis-je effectuer une recherche et un remplacement récursifs? En d'autres termes, je souhaite remplacer chaque occurrence de "foo" par "bar" dans tous les fichiers de ce répertoire et de ses sous-répertoires.
bash
shell
zsh
find-and-replace
Nathan Long
la source
la source
Réponses:
Cette commande le fera (testé sur Mac OS X Lion et Kubuntu Linux).
Voilà comment cela fonctionne:
find . -type f -name '*.txt'
trouve, dans le répertoire courant (.
) et au-dessous, tous les fichiers normaux (-type f
) dont le nom se termine par.txt
|
passe le résultat de cette commande (une liste de noms de fichiers) à la commande suivantexargs
rassemble ces noms de fichiers et les remet un à un àsed
sed -i '' -e 's/foo/bar/g'
signifie "édite le fichier en place, sans sauvegarde, et effectue la substitution suivante (s/foo/bar
) plusieurs fois par ligne (/g
)" (voirman sed
)Notez que la partie "sans sauvegarde" de la ligne 4 me convient, car les fichiers que je modifie sont de toute façon sous contrôle de version. Je peux donc facilement les annuler en cas d'erreur.
la source
-print0
option. Votre commande échouera sur les fichiers avec des espaces, etc. dans leur nom.find -name '*.txt' -exec sed -i 's/foo/bar/g' {} +
nous ferons tout cela avec GNU Find.sed: can't read : No such file or directory
quand je coursfind . -name '*.md' -print0 | xargs -0 sed -i '' -e 's/ä/ä/g'
, maisfind . -name '*.md' -print0
donne une liste de nombreux fichiers.-i
le''
''
après lesed -i
quel est le''
rôle?Cela supprime la
xargs
dépendance.la source
sed
et échouera donc sur la plupart des systèmes. GNUsed
vous demande de ne pas mettre d’espace entre-i
et''
.Si vous utilisez Git, vous pouvez faire ceci:
-l
répertorie uniquement les noms de fichiers.-z
affiche un octet nul après chaque résultat.J'ai fini par le faire, car certains fichiers d'un projet ne comportaient pas de nouvelle ligne à la fin du fichier et sed ajoutait une nouvelle ligne même si aucun autre changement n'était apporté. (Pas de commentaire sur le point de savoir si les fichiers doivent avoir une nouvelle ligne à la fin.)
la source
find ... -print0 | xargs -0 sed ...
solutions prend non seulement beaucoup plus de temps, mais ajoute également des lignes nouvelles aux fichiers qui n'en ont pas déjà, ce qui est une gêne lors du travail dans un dépôt Git.git grep
est éclairant rapidement par comparaison.Voici ma fonction zsh / perl que j'utilise pour cela:
Et je l'exécuterais en utilisant
(par exemple)
la source
Essayer:
Testé sur Ubuntu 12.04.
Cette commande NE fonctionnera PAS si les noms de sous-répertoires et / ou les noms de fichiers contiennent des espaces, mais si vous les avez, n'utilisez pas cette commande car elle ne fonctionnera pas.
Il est généralement déconseillé d'utiliser des espaces dans les noms de répertoire et les noms de fichiers.
http://linuxcommand.org/lc3_lts0020.php
Regardez "Faits importants sur les noms de fichiers"
la source
Utiliser ce script shell
J'utilise maintenant ce script shell, qui combine des éléments des autres réponses et de la recherche sur le Web. Je l'ai placé dans un fichier appelé
change
dans un dossier sur mon ordinateur$PATH
et l'a faitchmod +x change
.la source
Mon cas d'utilisation était que je voulais remplacer
foo:/Drive_Letter
par.foo:/bar/baz/xyz
Dans mon cas, j'ai pu le faire avec le code suivant. J'étais dans le même répertoire que celui où se trouvaient la plupart des fichiers.espérons que cela a aidé.
la source
La commande suivante a bien fonctionné sous Ubuntu et CentOS; Cependant, sous OS XI, les erreurs continuaient à se produire:
Lorsque j'ai essayé de passer les paramètres via xargs, cela a bien fonctionné, sans erreur:
la source
-i
pour-i ''
est probablement plus pertinent que le fait que vous avez changé-exec
pour-print0 | xargs -0
. BTW, vous n'avez probablement pas besoin de la-e
.Ce qui précède a fonctionné comme un charme, mais avec les répertoires liés, je dois y ajouter un
-L
drapeau. La version finale ressemble à:la source