Comment faire une recherche / remplacement récursif d'une chaîne avec awk ou sed?

679

Comment trouver et remplacer chaque occurrence de:

subdomainA.example.com

avec

subdomainB.example.com

dans chaque fichier texte sous l' /home/www/arborescence de répertoires récursivement?

Tedd
la source
93
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.

Pour plus d'informations, voir man find.

reedwolf
la source
132
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.

John Zwinck
la source
50
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
la source
1
@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.

I159
la source
@ 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'
Russe employé
la source
2
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.
Charles Duffy
34

Pour moi, la solution la plus simple à retenir est https://stackoverflow.com/a/2113224/565525 , à savoir:

sed -i '' -e 's/subdomainA/subdomainB/g' $(find /home/www/ -type f)

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: utilisation find -execou xargssolution décrite ci-dessus.

Robert Lujo
la source
4
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.
tripleee
30

Pour tous ceux qui utilisent Silver Searcher ( ag)

ag SearchString -l0 | xargs -0 sed -i 's/SearchString/Replacement/g'

É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.

Jacob Wang
la source
16

Un joli oneliner en plus. Utilisation de git grep.

git grep -lz 'subdomainA.example.com' | xargs -0 perl -i'' -pE "s/subdomainA.example.com/subdomainB.example.com/g"
Jimmy Kane
la source
3
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
domdambrogia
la source
13

Celui-ci est compatible avec les dépôts git, et un peu plus simple:

Linux:

git grep -l 'original_text' | xargs sed -i 's/original_text/new_text/g'

Mac:

git grep -l 'original_text' | xargs sed -i '' -e 's/original_text/new_text/g'

(Merci à http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/ )

seddonym
la source
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é.

perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

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.

unutbu
la source
8

J'en avais juste besoin et je n'étais pas satisfait de la vitesse des exemples disponibles. J'ai donc créé le mien:

cd /var/www && ack-grep -l --print0 subdomainA.example.com | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'

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.

Henno
la source
Nice, mais grep -ril 'subdomainA' *est loin d'être aussi rapide que grep -Hr 'subdomainA' * | cut -d: -f1.
trusktr
@Henno: juste une question: comment exclure des fichiers binaires (fichiers exécutables) ?
user2284570
ack-grep le fait automatiquement pour vous.
Henno
@Henno: Comprend-il des scripts shell?
user2284570
Oui. Voici une liste complète des types de fichiers pris en charge: Beyondgrep.com/documentation
Henno
6

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'
inetphantom
la source
6

Manière la plus simple de remplacer ( tous les fichiers, répertoire, récursif )

find . -type f -not -path '*/\.*' -exec sed -i 's/foo/bar/g' {} +

Remarque: Parfois, vous devrez peut-être ignorer certains fichiers cachés, c'est-à-dire que .gitvous pouvez utiliser la commande ci-dessus.

Si vous souhaitez inclure l'utilisation de fichiers cachés,

find . -type f  -exec sed -i 's/foo/bar/g' {} +

Dans les deux cas, la chaîne foosera remplacée par une nouvelle chaînebar

Sazzad Hissain Khan
la source
5

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.

MadMan2064
la source
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,

for file in `find /home/www -type f`
do
   awk '{gsub(/subdomainA.example.com/,"subdomainB.example.com"); print $0;}' $file > ./tempFile && mv ./tempFile $file;
done

J'espère que cela vous aidera !!!

sarath kumar
la source
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' *`
RikHic
la source
1
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}"
    fi

done
petrus4
la source
4

Selon cet article de blog:

find . -type f | xargs perl -pi -e 's/oldtext/newtext/g;'
J.Hpour
la source
Comment échappez-vous aux barres obliques /?. Par exemple, je veux remplacer les adresses IP: xxx.xxx.xxx.xxxpourxxx.xxx.xxx.xxx/folder
Pathros
Vous pouvez échapper au /avec \. Par exemple:find . -type f | xargs perl -pi -e 's/xxx.xxx.xxx.xxx\/folder/newtext/g;'
J.Hpour
3

Si cela ne vous dérange pas d'utiliser vimavec grepou des findoutils, 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 vimsuivant un schéma similaire à celui fourni sur le lien donné:

    • :bufdo %s#string#replacement#gc | update
mzcl-mn
la source
2

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).

Heureux les semeurs!

Raphvanns
la source
2

juste pour éviter de changer aussi

  • NearlysubdomainA.example.com
  • subdomainA.example.comp.other

mais reste

  • subdomainA.example.com.IsIt.good

(peut-être pas bon dans l'idée derrière la racine du domaine)

find /home/www/ -type f -exec sed -i 's/\bsubdomainA\.example\.com\b/\1subdomainB.example.com\2/g' {} \;
NeronLeVelu
la source
2

J'utilise juste des hauts:

find . -name '*.[c|cc|cp|cpp|m|mm|h]' -print0 |  xargs -0 tops -verbose  replace "verify_noerr(<b args>)" with "__Verify_noErr(<args>)" \
replace "check(<b args>)" with "__Check(<args>)" 
tgunr
la source
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'
bbarker
la source
1

Pour Qshell (qsh) sur IBMi, pas bash comme balisé par OP.

Limitations des commandes qsh:

  • find n'a pas l'option -print0
  • xargs n'a pas l'option -0
  • sed n'a pas l'option -i

Ainsi la solution dans qsh:

    PATH='your/path/here'
    SEARCH=\'subdomainA.example.com\'
    REPLACE=\'subdomainB.example.com\'

    for file in $( find ${PATH} -P -type f ); do

            TEMP_FILE=${file}.${RANDOM}.temp_file

            if [ ! -e ${TEMP_FILE} ]; then
                    touch -C 819 ${TEMP_FILE}

                    sed -e 's/'$SEARCH'/'$REPLACE'/g' \
                    < ${file} > ${TEMP_FILE}

                    mv ${TEMP_FILE} ${file}
            fi
    done

Mises en garde:

  • La solution exclut la gestion des erreurs
  • Not Bash comme taggé par OP
Christoff Erasmus
la source
Cela a quelques problèmes embêtants avec la citation ainsi que la lecture des lignes avec for.
tripleee
1

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:

find . \( ! -regex '.*/\..*' \) -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g'
Marcus Floyd
la source
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
Pawel
la source
@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.

Perséides
la source
1
perl -p -i -e 's/oldthing/new_thingy/g' `grep -ril oldthing *`
Sheena
la source
1
Ne pas utiliser awk/ sed, mais perl est courant (sauf les systèmes / embarqués avec busybox uniquement).
pevik
1

pour modifier plusieurs fichiers (et enregistrer une sauvegarde sous *.bak):

perl -p -i -e "s/\|/x/g" *

prendra tous les fichiers dans le répertoire et les remplacera |par x appelé «tarte Perl» (facile comme tarte)

Stenemo
la source
Pas récursif dans les répertoires.
PKHunter
il est possible d'y rediriger ce qui le rend très ajustable, y compris via des répertoires. josephscott.org/archives/2005/08/... et unix.stackexchange.com/questions/101415/...
Stenemo