Astuce: ne faites pas ce qui suit dans une arborescence de paiement svn ... cela écrasera les fichiers du dossier magique .svn.
J.Polfer
7
oh mon dieu c'est exactement ce que je viens de faire. Mais cela a fonctionné et ne semble pas avoir fait de mal. Quel est le pire qui puisse arriver?
J. Katzwinkel
5
@ J.Katzwinkel: à tout le moins, cela peut corrompre les sommes de contrôle, ce qui peut corrompre votre référentiel.
ninjagecko
3
Astuce rapide pour toutes les personnes utilisant sed: cela ajoutera des retours à la ligne à vos fichiers. Si vous ne les voulez pas, faites d'abord un find-replace qui ne correspondra à rien, et validez-le dans git. Ensuite, faites le vrai. Rebase ensuite de manière interactive et supprime le premier.
funroll
5
Vous pouvez exclure un répertoire, tel que git, des résultats en utilisant -path ./.git -prune -oin find . -path ./.git -prune -o -type f -name '*matchThisText*' -print0avant de
diriger
Réponses:
852
find /home/www \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'
-print0indique findd'imprimer chacun des résultats séparés par un caractère nul, plutôt qu'une nouvelle ligne. Dans le cas peu probable où votre répertoire contient des fichiers avec des retours à la ligne dans les noms, cela permet toujours de xargstravailler sur les noms de fichiers corrects.
\( -type d -name .git -prune \)est une expression qui ignore complètement tous les répertoires nommés .git. Vous pouvez facilement l'étendre, si vous utilisez SVN ou si vous avez d'autres dossiers que vous souhaitez conserver - il suffit de faire correspondre d'autres noms. C'est à peu près équivalent à -not -path .git, mais plus efficace, car plutôt que de vérifier chaque fichier du répertoire, il l'ignore complètement. le-o après est nécessaire en raison de la façon dont -prunefonctionne réellement.
Sur OSX, vous pouvez rencontrer des sed: 1: "...": invalid command code .problèmes. Il semble que l'option -i attend l'extension et analyse la 's/../...'commande. Solution: passez l'extension '' à l'option -i comme sed -i '' 's/....
Robert Lujo du
6
Remarque: si vous l'utilisez sur un répertoire et que vous vous demandez pourquoi svn stne montre aucun changement, c'est parce que vous avez également modifié des fichiers dans les répertoires .svn! Utilisez find . -maxdepth 1 -type f -print0 | xargs -0 sed -i 's/toreplace/replaced/g'plutôt.
ACK_stoverflow
57
Faites également attention si vous êtes dans un dépôt git. Je pensais que j'étais intelligent en testant cela sur une branche claire afin que je puisse revenir en arrière si cela faisait quelque chose de mal, mais à la place, j'ai corrompu mon index git.
Ciryon
13
Utilisez-le grep -r 'hello' -l --null . | xargs -0 sed -i 's#hello#world#g'pour éviter de modifier des fichiers non liés (sed peut changer l'encodage des fichiers).
caiguanhao
6
"mais a corrompu mon index git." Ne vous inquiétez pas trop de ce que vous pouvez faire find .git ... | ... 'sed -i s/(the opposite from before)/g'pour corriger votre index git
Massey101
259
Remarque : N'exécutez pas cette commande sur un dossier comprenant un dépôt git - les modifications apportées à .git pourraient corrompre votre index git.
find /home/www/-type f -exec \
sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'{}+
Comparé à d'autres réponses ici, c'est plus simple que la plupart et utilise sed au lieu de perl, ce qui était ce que la question initiale demandait.
Notez que si vous utilisez BSD sed (y compris sur Mac OS X), vous devrez donner une chaîne de caractères vide explicite à l' -ioption de sed . Soit: sed -i '' 's/original/replacement/g'
Nathan Craike
2
@JohnZwinck Mon erreur, j'ai raté le +. Curieusement, la solution de Nikita fonctionne plus vite pour moi.
Sam
6
@AoeAoe: Le +réduit considérablement le nombre de sedprocessus générés. C'est plus efficace.
John Zwinck
4
Comment puis-je le faire en toute sécurité dans un dossier avec un dépôt git?
Hatchepsout
20
Il est sûr d'exécuter sur un dossier contenant un repo git si vous excluez le repo de vos résultats FIND: find . -not -path '*/\.git*' -type f ....
Dale Anderson
214
Le moyen le plus simple pour moi est
grep -rl oldtext .| xargs sed -i 's/oldtext/newtext/g'
@Anatoly: juste une question: comment puis-je exclure des fichiers binaires (fichiers exécutables) ?
user2284570
3
@ user2284570 Utilisez les drapeaux -Iou --binary-file=without-matchgrep.
Zéychin
34
Cela fonctionne particulièrement bien lorsque vous devez exclure des répertoires, comme avec .svn. Par exemple:grep -rl oldtext . --exclude-dir=.svn | xargs sed -i 's/oldtext/newtext/g'
phyatt
11
brew install gnu-sedet utiliser gsedsur OSX pour éviter un monde de douleur.
P i
1
Veuillez faire attention les gars, si votre projet est git versionnée, utilisez plutôt: git grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'. ce n'est pas agréable du tout de f * ck jusqu'à votre .gitdir
Paolo
61
Tous les trucs sont presque les mêmes, mais j'aime celui-ci:
find <mydir>-type f -exec sed -i 's/<string1>/<string2>/g'{}+
find <mydir>: recherchez dans le répertoire.
-type f:
Le fichier est de type: fichier normal
-exec command {} +:
Cette variante de l'action -exec exécute la commande spécifiée sur les fichiers sélectionnés, mais la ligne de commande est créée en ajoutant à la fin chaque nom de fichier sélectionné; le nombre total d'appels de la commande sera bien inférieur au nombre de fichiers correspondants. La ligne de commande est construite de la même manière que xargs construit ses lignes de commande. Une seule instance de `{} 'est autorisée dans la commande. La commande est exécutée dans le répertoire de départ.
@ user2284570 avec -exec? Essayez de définir le chemin vers l'exécutable au lieu d'un nom d'outil.
I159
@ I159: Non: exclut les binaires exécutables (mais inclut les scripts shell) .
user2284570
8
@ I159 Cette réponse n'est-elle pas identique à celle de John Zwinck ?
Réinstallez Monica s'il vous plaît
1
@ user2284570 Le concept de "fichier binaire" n'est pas entièrement bien défini. Vous pouvez utiliser la filecommande pour essayer de déterminer le type de chaque fichier, mais les variations aléatoires de sa sortie peuvent être légèrement déroutantes. L' option -I(aka --mime) aide quelque peu, ou --mime-typesi vous en avez. Comment refactoriser exactement cette doublure soignée pour ce faire est malheureusement hors de portée pour cette petite boîte de commentaires. Peut-être posez-vous une question distincte si vous avez besoin d'aide? (Ajoutez peut-être un commentaire avec un lien ici alors.)
tripleee
1
la réponse la plus nette! merci compagnon
jukerok
39
cd /home/www && find .-type f -print0 |
xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'
Je suis curieux, y a-t-il une raison d'utiliser -print0et xargsau lieu de -execou -execdir?
Philipp
4
Il y a: à partir de "man find": la commande spécifiée est exécutée une fois pour chaque fichier correspondant. Autrement dit, s'il y a 2000 fichiers dans / home / www, alors 'find ... -exec ...' entraînera 2000 invocations de perl; alors que «trouver ... | xargs ... 'n'invoquera perl qu'une ou deux fois (en supposant ARG_MAX d'environ 32 Ko et une longueur moyenne de nom de fichier de 20).
Employé russe
2
@Employed Russian: c'est pourquoi vous utiliseriez find -exec command {} +- cela évite les invocations excessives de la commande comme xargs, mais sans le processus séparé.
John Zwinck
2
Sur quelle plateforme? La solution xargs est portable, les invocations "magiques" de "find ... -exec" qui n'invoquent pas de sous-processus pour chaque fichier trouvé ne le sont pas.
Employé russe
4
@EmployedRussian, find -exec ... {} +est spécifié par POSIX depuis 2006.
REMARQUE : s'il y a trop de fichiers à traiter, vous obtiendrez Argument list too long. Solution: utilisation find -execou xargssolution décrite ci-dessus.
Le workarounddevrait être la syntaxe préférée dans tous les cas.
Réinstallez Monica,
1
Le problème avec la substitution de commande $(find...)est qu'il n'y a aucun moyen pour le shell de gérer les noms de fichiers avec des espaces ou d'autres métacaractères du shell. Si vous savez que ce n'est pas un problème, cette approche est très bien; mais nous avons trop de questions où les gens n'ont pas été avertis de ce problème ou n'ont pas compris l'avertissement.
Bonne idée si vous travaillez dans un dépôt git car vous ne risquez pas d'écraser .git / contents (comme indiqué dans les commentaires d'une autre réponse).
mahemoff
1
Merci, je l'utilise comme une fonction bash refactor() { echo "Replacing $1 by $2 in all files in this git repository." git grep -lz $1| xargs -0 perl -i'' -pE "s/$1/$2/g" }Utilisation, par exemple pour remplacer 'word' par 'sword': refactor word swordvérifiez ensuite ce qu'il a fait git diff.
Paul Rougieux
16
Pour réduire les fichiers à sedparcourir récursivement , vous pouvez greppour votre instance de chaîne:
grep -rl <oldstring>/path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
Si vous exécutez, man grepvous remarquerez que vous pouvez également définir un--exlude-dir="*.git" indicateur si vous souhaitez omettre de rechercher dans les répertoires .git, en évitant les problèmes d'index git comme d'autres l'ont poliment souligné.
Vous conduisant à:
grep -rl --exclude-dir="*.git"<oldstring>/path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
Il est plus sage d'utiliser git-grepl' -zoption avec xargs -0.
gniourf_gniourf
git grepévidemment n'a de sens que dans un gitrepo. Le remplacement général serait grep -r.
tripleee
@gniourf_gniourf Pouvez-vous expliquer?
Petr Peller le
2
@PetrPeller: avec -z, git-grepséparera les champs de sortie par des octets nuls au lieu de nouvelles lignes; et avec -0, xargslira l'entrée séparée par des octets nuls, au lieu de blancs (et ne fera pas de trucs bizarres avec des guillemets). Donc , si vous ne voulez pas la commande de pause si les fichiers contiennent des espaces, des citations ou d' autres personnages drôles, la commande est: git grep -z -l 'original_text' | xargs -0 sed ....
gniourf_gniourf
10
find /home/www/-type f -exec perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'{}+
find /home/www/ -type f listera tous les fichiers dans / home / www / (et ses sous-répertoires). L'indicateur "-exec" indique à find d'exécuter la commande suivante sur chaque fichier trouvé.
est la commande exécutée sur les fichiers (plusieurs à la fois). Le {}obtient remplacé par des noms de fichiers. Le +à la fin de la commande indique findde créer une commande pour de nombreux noms de fichiers.
Par le find page de manuel: "La ligne de commande est construite de la même manière que xargs construit ses lignes de commande."
Ainsi, il est possible d'atteindre votre objectif (et de gérer les noms de fichiers contenant des espaces) sans utiliser xargs -0, ou -print0.
Ack-grep est très efficace pour trouver des fichiers pertinents. Cette commande a remplacé ~ 145 000 fichiers par un jeu d'enfant alors que d'autres ont pris tellement de temps que je ne pouvais pas attendre qu'ils finissent.
Une méthode simple si vous devez exclure des répertoires ( --exclude-dir=.svn) et que vous pouvez également avoir des noms de fichier avec des espaces (en utilisant 0 octet avec grep -Zetxargs -0
grep -rlZ oldtext .--exclude-dir=.svn | xargs -0 sed -i 's/oldtext/newtext/g'
grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done
Je suppose que la plupart des gens ne savent pas qu'ils peuvent diriger quelque chose dans un "fichier en lecture" et cela évite ces désagréables arguments -print0, tout en prévoyant des espaces dans les noms de fichiers.
En ajoutant un echoavant le sed, vous pouvez voir quels fichiers vont changer avant de le faire.
La raison -print0est utile car elle gère les cas qui while readne peuvent tout simplement pas être traités - une nouvelle ligne est un caractère valide dans un nom de fichier Unix, donc pour que votre code soit complètement robuste, il doit également faire face à ces noms de fichiers. (En outre, vous voulez read -réviter certains comportements hérités POSIX hérités read.)
tripleee
De plus, le sedest un no-op s'il n'y a pas de correspondance, donc ce grepn'est pas vraiment nécessaire; bien que ce soit une optimisation utile pour éviter de réécrire des fichiers qui ne contiennent aucune correspondance, si vous en avez beaucoup ou si vous voulez éviter de mettre à jour les horodatages des fichiers inutilement.
tripleee
5
Vous pouvez utiliser awk pour résoudre ce problème comme ci-dessous,
Fonctionne sur MacOs sans aucun problème! Toutes les sedcommandes basées ont échoué lorsque des fichiers binaires ont été inclus, même avec les paramètres spécifiques osx.
Jankapunkt
Attention ... cela explosera si l'un des fichiers findrenvoyés contient un espace dans leur nom! Son utilisation est beaucoup plus sûre while read: stackoverflow.com/a/9612560/1938956
Soren Bjornstad
4
Essaye ça:
sed -i 's/subdomainA/subdomainB/g'`grep -ril 'subdomainA' *`
Salut @RikHic, bon conseil - pensais à quelque chose comme ça; malheureusement, le formatage ci-dessus ne s'est pas tout à fait bien passé :) Je vais donc essayer avec une balise pre (ne fonctionne pas) - donc avec des backticks d'échappement alors: sed -i 's/subdomainA/subdomainB/g'` grep -ril 'subdomainA' /home/www/*` - cela ne semble toujours pas très bon, mais devrait survivre copypaste :) A bientôt!
2011
4
#!/usr/local/bin/bash -x
find */home/www -type f |while read files
do
sedtest=$(sed -n '/^/,/$/p'"${files}"| sed -n '/subdomainA/p')if["${sedtest}"]then
sed s'/subdomainA/subdomainB/'g "${files}">"${files}".tmp
mv "${files}".tmp "${files}"fidone
grep récursivement pour la chaîne que vous souhaitez remplacer dans un certain chemin, et prenez uniquement le chemin complet du fichier correspondant. (ce serait le $(grep 'string' 'pathname' -Rl).
(facultatif) si vous souhaitez effectuer une pré-sauvegarde de ces fichiers sur un répertoire centralisé, vous pouvez peut-être également utiliser ceci: cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'
après cela, vous pouvez modifier / remplacer à volonté en vimsuivant un schéma similaire à celui fourni sur le lien donné:
Un peu vieille école mais cela fonctionnait sous OS X.
Il y a peu de ruses:
• Ne modifiera que les fichiers avec extension .sls dans le répertoire courant
• .doit être échappé pour assurersed ne pas les évaluer comme "n'importe quel caractère"
• ,est utilisé comme seddélimiteur au lieu de l'habituel/
Notez également qu'il s'agit de modifier un modèle Jinja pour passer un variabledans le chemin d'un import(mais cela est hors sujet).
Tout d'abord, vérifiez que votre commande sed fait ce que vous voulez (cela n'imprimera que les modifications sur stdout, cela ne changera pas les fichiers):
for file in $(find .-name *.sls -type f);do echo -e "\n$file: "; sed 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file;done
Modifiez la commande sed au besoin, une fois que vous êtes prêt à apporter des modifications:
for file in $(find .-name *.sls -type f);do echo -e "\n$file: "; sed -i '''s,foo\.bar,foo/bar/\"+baz+\"/,g' $file;done
Remarquez que -i ''dans la commande sed , je ne voulais pas créer une sauvegarde des fichiers originaux (comme expliqué dans les modifications sur place avec sed sur OS X ou dans le commentaire de Robert Lujo sur cette page).
plus un pour `` *. [c | cc | cp | cpp | m | mm | h] ''
FractalSpace
2
Voici une version qui devrait être plus générale que la plupart; il ne nécessite pas find(en utilisant à la duplace), par exemple. Cela nécessite xargs, qui ne se trouvent que dans certaines versions de Plan 9 (comme 9front).
du -a | awk -F' ''{ print $2 }'| xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'
Si vous souhaitez ajouter des filtres comme les extensions de fichier, utilisez grep:
du -a | grep "\.scala$"| awk -F' ''{ print $2 }'| xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'
Les parenthèses semblent superflues. Cela avait précédemment une erreur de formatage qui le rendait inutilisable (le rendu Markdown mangerait certains caractères de l'expression régulière).
tripleee
1
Utilisation de la combinaison de grepetsed
for pp in $(grep -Rl looking_for_string)do
sed -i 's/looking_for_string/something_other/g'"${pp}"done
@tripleee J'ai un peu modifié cela. Dans ce cas, affichez la grep -Rl patternliste des fichiers générés par la commande où se trouve le modèle. Les fichiers ne sont pas lus en forboucle.
Pawel
Hein? Vous avez encore une forboucle; si un nom de fichier renvoyé contient un espace, il ne fonctionnera pas correctement, car le shell tokenise la forliste des arguments. Mais alors vous utilisez la variable de nom de fichier sans guillemets à l'intérieur de la boucle, donc elle s'y briserait à la place si vous corrigiez cela. La correction de ces bogues restants rendrait la vôtre identique à la réponse de @ MadMan2064.
tripleee
@tripleee oui, c'est vrai, j'ai raté ça.
Pawel
1
Pour remplacer toutes les occurrences dans un référentiel git, vous pouvez utiliser:
git ls-files -z | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'
Voir Liste des fichiers dans le dépôt git local? pour d'autres options pour répertorier tous les fichiers dans un référentiel. Les -zoptions indiquent à git de séparer les noms de fichiers par un octet zéro, ce qui garantit que xargs(avec l'option -0) peut séparer les noms de fichiers, même s'ils contiennent des espaces ou autres.
-path ./.git -prune -o
infind . -path ./.git -prune -o -type f -name '*matchThisText*' -print0
avant deRéponses:
-print0
indiquefind
d'imprimer chacun des résultats séparés par un caractère nul, plutôt qu'une nouvelle ligne. Dans le cas peu probable où votre répertoire contient des fichiers avec des retours à la ligne dans les noms, cela permet toujours dexargs
travailler sur les noms de fichiers corrects.\( -type d -name .git -prune \)
est une expression qui ignore complètement tous les répertoires nommés.git
. Vous pouvez facilement l'étendre, si vous utilisez SVN ou si vous avez d'autres dossiers que vous souhaitez conserver - il suffit de faire correspondre d'autres noms. C'est à peu près équivalent à-not -path .git
, mais plus efficace, car plutôt que de vérifier chaque fichier du répertoire, il l'ignore complètement. le-o
après est nécessaire en raison de la façon dont-prune
fonctionne réellement.Pour plus d'informations, voir
man find
.la source
sed: 1: "...": invalid command code .
problèmes. Il semble que l'option -i attend l'extension et analyse la's/../...'
commande. Solution: passez l'extension '' à l'option -i commesed -i '' 's/...
.svn st
ne montre aucun changement, c'est parce que vous avez également modifié des fichiers dans les répertoires .svn! Utilisezfind . -maxdepth 1 -type f -print0 | xargs -0 sed -i 's/toreplace/replaced/g'
plutôt.grep -r 'hello' -l --null . | xargs -0 sed -i 's#hello#world#g'
pour éviter de modifier des fichiers non liés (sed peut changer l'encodage des fichiers).find .git ... | ... 'sed -i s/(the opposite from before)/g'
pour corriger votre index gitRemarque : N'exécutez pas cette commande sur un dossier comprenant un dépôt git - les modifications apportées à .git pourraient corrompre votre index git.
Comparé à d'autres réponses ici, c'est plus simple que la plupart et utilise sed au lieu de perl, ce qui était ce que la question initiale demandait.
la source
-i
option de sed . Soit:sed -i '' 's/original/replacement/g'
+
réduit considérablement le nombre desed
processus générés. C'est plus efficace.find . -not -path '*/\.git*' -type f ...
.Le moyen le plus simple pour moi est
la source
-I
ou--binary-file=without-match
grep..svn
. Par exemple:grep -rl oldtext . --exclude-dir=.svn | xargs sed -i 's/oldtext/newtext/g'
brew install gnu-sed
et utilisergsed
sur OSX pour éviter un monde de douleur.git grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'
. ce n'est pas agréable du tout de f * ck jusqu'à votre.git
dirTous les trucs sont presque les mêmes, mais j'aime celui-ci:
find <mydir>
: recherchez dans le répertoire.-type f
:-exec command {} +
:la source
file
commande pour essayer de déterminer le type de chaque fichier, mais les variations aléatoires de sa sortie peuvent être légèrement déroutantes. L' option-I
(aka--mime
) aide quelque peu, ou--mime-type
si vous en avez. Comment refactoriser exactement cette doublure soignée pour ce faire est malheureusement hors de portée pour cette petite boîte de commentaires. Peut-être posez-vous une question distincte si vous avez besoin d'aide? (Ajoutez peut-être un commentaire avec un lien ici alors.)la source
-print0
etxargs
au lieu de-exec
ou-execdir
?find -exec command {} +
- cela évite les invocations excessives de la commande comme xargs, mais sans le processus séparé.find -exec ... {} +
est spécifié par POSIX depuis 2006.Pour moi, la solution la plus simple à retenir est https://stackoverflow.com/a/2113224/565525 , à savoir:
REMARQUE :
-i ''
résout le problème OSXsed: 1: "...": invalid command code .
REMARQUE : s'il y a trop de fichiers à traiter, vous obtiendrez
Argument list too long
. Solution: utilisationfind -exec
ouxargs
solution décrite ci-dessus.la source
workaround
devrait être la syntaxe préférée dans tous les cas.$(find...)
est qu'il n'y a aucun moyen pour le shell de gérer les noms de fichiers avec des espaces ou d'autres métacaractères du shell. Si vous savez que ce n'est pas un problème, cette approche est très bien; mais nous avons trop de questions où les gens n'ont pas été avertis de ce problème ou n'ont pas compris l'avertissement.Pour tous ceux qui utilisent Silver Searcher (
ag
)Étant donné qu'ag ignore les fichiers / dossiers git / hg / svn par défaut, cela peut être exécuté en toute sécurité dans un référentiel.
la source
Un joli oneliner en plus. Utilisation de git grep.
la source
refactor() { echo "Replacing $1 by $2 in all files in this git repository." git grep -lz $1| xargs -0 perl -i'' -pE "s/$1/$2/g" }
Utilisation, par exemple pour remplacer 'word' par 'sword':refactor word sword
vérifiez ensuite ce qu'il a faitgit diff
.Pour réduire les fichiers à
sed
parcourir récursivement , vous pouvezgrep
pour votre instance de chaîne:Si vous exécutez,
man grep
vous remarquerez que vous pouvez également définir un--exlude-dir="*.git"
indicateur si vous souhaitez omettre de rechercher dans les répertoires .git, en évitant les problèmes d'index git comme d'autres l'ont poliment souligné.Vous conduisant à:
la source
Celui-ci est compatible avec les dépôts git, et un peu plus simple:
Linux:
Mac:
(Merci à http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/ )
la source
git-grep
l'-z
option avecxargs -0
.git grep
évidemment n'a de sens que dans ungit
repo. Le remplacement général seraitgrep -r
.-z
,git-grep
séparera les champs de sortie par des octets nuls au lieu de nouvelles lignes; et avec-0
,xargs
lira l'entrée séparée par des octets nuls, au lieu de blancs (et ne fera pas de trucs bizarres avec des guillemets). Donc , si vous ne voulez pas la commande de pause si les fichiers contiennent des espaces, des citations ou d' autres personnages drôles, la commande est:git grep -z -l 'original_text' | xargs -0 sed ...
.find /home/www/ -type f
listera tous les fichiers dans / home / www / (et ses sous-répertoires). L'indicateur "-exec" indique à find d'exécuter la commande suivante sur chaque fichier trouvé.est la commande exécutée sur les fichiers (plusieurs à la fois). Le
{}
obtient remplacé par des noms de fichiers. Le+
à la fin de la commande indiquefind
de créer une commande pour de nombreux noms de fichiers.Par le
find
page de manuel: "La ligne de commande est construite de la même manière que xargs construit ses lignes de commande."Ainsi, il est possible d'atteindre votre objectif (et de gérer les noms de fichiers contenant des espaces) sans utiliser
xargs -0
, ou-print0
.la source
J'en avais juste besoin et je n'étais pas satisfait de la vitesse des exemples disponibles. J'ai donc créé le mien:
Ack-grep est très efficace pour trouver des fichiers pertinents. Cette commande a remplacé ~ 145 000 fichiers par un jeu d'enfant alors que d'autres ont pris tellement de temps que je ne pouvais pas attendre qu'ils finissent.
la source
grep -ril 'subdomainA' *
est loin d'être aussi rapide quegrep -Hr 'subdomainA' * | cut -d: -f1
.Une méthode simple si vous devez exclure des répertoires (
--exclude-dir=.svn
) et que vous pouvez également avoir des noms de fichier avec des espaces (en utilisant 0 octet avecgrep -Z
etxargs -0
la source
Manière la plus simple de remplacer ( tous les fichiers, répertoire, récursif )
Remarque: Parfois, vous devrez peut-être ignorer certains fichiers cachés, c'est-à-dire que
.git
vous pouvez utiliser la commande ci-dessus.Si vous souhaitez inclure l'utilisation de fichiers cachés,
Dans les deux cas, la chaîne
foo
sera remplacée par une nouvelle chaînebar
la source
grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done
Je suppose que la plupart des gens ne savent pas qu'ils peuvent diriger quelque chose dans un "fichier en lecture" et cela évite ces désagréables arguments -print0, tout en prévoyant des espaces dans les noms de fichiers.
En ajoutant un
echo
avant le sed, vous pouvez voir quels fichiers vont changer avant de le faire.la source
-print0
est utile car elle gère les cas quiwhile read
ne peuvent tout simplement pas être traités - une nouvelle ligne est un caractère valide dans un nom de fichier Unix, donc pour que votre code soit complètement robuste, il doit également faire face à ces noms de fichiers. (En outre, vous voulezread -r
éviter certains comportements hérités POSIX héritésread
.)sed
est un no-op s'il n'y a pas de correspondance, donc cegrep
n'est pas vraiment nécessaire; bien que ce soit une optimisation utile pour éviter de réécrire des fichiers qui ne contiennent aucune correspondance, si vous en avez beaucoup ou si vous voulez éviter de mettre à jour les horodatages des fichiers inutilement.Vous pouvez utiliser awk pour résoudre ce problème comme ci-dessous,
J'espère que cela vous aidera !!!
la source
sed
commandes basées ont échoué lorsque des fichiers binaires ont été inclus, même avec les paramètres spécifiques osx.find
renvoyés contient un espace dans leur nom! Son utilisation est beaucoup plus sûrewhile read
: stackoverflow.com/a/9612560/1938956Essaye ça:
la source
sed -i 's/subdomainA/subdomainB/g'
`grep -ril 'subdomainA' /home/www/*
` - cela ne semble toujours pas très bon, mais devrait survivre copypaste :) A bientôt!la source
Selon cet article de blog:
la source
/
?. Par exemple, je veux remplacer les adresses IP:xxx.xxx.xxx.xxx
pourxxx.xxx.xxx.xxx/folder
/
avec \. Par exemple:find . -type f | xargs perl -pi -e 's/xxx.xxx.xxx.xxx\/folder/newtext/g;'
Si cela ne vous dérange pas d'utiliser
vim
avecgrep
ou desfind
outils, vous pouvez suivre la réponse donnée par l'utilisateur Gert dans ce lien -> Comment faire un remplacement de texte dans une grande hiérarchie de dossiers? .Voici l'affaire:
grep récursivement pour la chaîne que vous souhaitez remplacer dans un certain chemin, et prenez uniquement le chemin complet du fichier correspondant. (ce serait le
$(grep 'string' 'pathname' -Rl)
.(facultatif) si vous souhaitez effectuer une pré-sauvegarde de ces fichiers sur un répertoire centralisé, vous pouvez peut-être également utiliser ceci:
cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'
après cela, vous pouvez modifier / remplacer à volonté en
vim
suivant un schéma similaire à celui fourni sur le lien donné::bufdo %s#string#replacement#gc | update
la source
Un peu vieille école mais cela fonctionnait sous OS X.
Il y a peu de ruses:
• Ne modifiera que les fichiers avec extension
.sls
dans le répertoire courant•
.
doit être échappé pour assurersed
ne pas les évaluer comme "n'importe quel caractère"•
,
est utilisé commesed
délimiteur au lieu de l'habituel/
Notez également qu'il s'agit de modifier un modèle Jinja pour passer un
variable
dans le chemin d'unimport
(mais cela est hors sujet).Tout d'abord, vérifiez que votre commande sed fait ce que vous voulez (cela n'imprimera que les modifications sur stdout, cela ne changera pas les fichiers):
Modifiez la commande sed au besoin, une fois que vous êtes prêt à apporter des modifications:
Remarquez que
-i ''
dans la commande sed , je ne voulais pas créer une sauvegarde des fichiers originaux (comme expliqué dans les modifications sur place avec sed sur OS X ou dans le commentaire de Robert Lujo sur cette page).Heureux les semeurs!
la source
juste pour éviter de changer aussi
mais reste
(peut-être pas bon dans l'idée derrière la racine du domaine)
la source
J'utilise juste des hauts:
la source
Voici une version qui devrait être plus générale que la plupart; il ne nécessite pas
find
(en utilisant à ladu
place), par exemple. Cela nécessitexargs
, qui ne se trouvent que dans certaines versions de Plan 9 (comme 9front).Si vous souhaitez ajouter des filtres comme les extensions de fichier, utilisez
grep
:la source
Pour Qshell (qsh) sur IBMi, pas bash comme balisé par OP.
Limitations des commandes qsh:
Ainsi la solution dans qsh:
Mises en garde:
la source
for
.Si vous vouliez l'utiliser sans détruire complètement votre référentiel SVN, vous pouvez dire à 'find' d'ignorer tous les fichiers cachés en faisant:
la source
Utilisation de la combinaison de
grep
etsed
la source
grep -Rl pattern
liste des fichiers générés par la commande où se trouve le modèle. Les fichiers ne sont pas lus enfor
boucle.for
boucle; si un nom de fichier renvoyé contient un espace, il ne fonctionnera pas correctement, car le shell tokenise lafor
liste des arguments. Mais alors vous utilisez la variable de nom de fichier sans guillemets à l'intérieur de la boucle, donc elle s'y briserait à la place si vous corrigiez cela. La correction de ces bogues restants rendrait la vôtre identique à la réponse de @ MadMan2064.Pour remplacer toutes les occurrences dans un référentiel git, vous pouvez utiliser:
Voir Liste des fichiers dans le dépôt git local? pour d'autres options pour répertorier tous les fichiers dans un référentiel. Les
-z
options indiquent à git de séparer les noms de fichiers par un octet zéro, ce qui garantit quexargs
(avec l'option-0
) peut séparer les noms de fichiers, même s'ils contiennent des espaces ou autres.la source
la source
awk
/sed
, mais perl est courant (sauf les systèmes / embarqués avec busybox uniquement).pour modifier plusieurs fichiers (et enregistrer une sauvegarde sous
*.bak
):prendra tous les fichiers dans le répertoire et les remplacera
|
par x appelé «tarte Perl» (facile comme tarte)la source