La commande suivante modifie correctement le contenu de 2 fichiers.
sed -i 's/abc/xyz/g' xaa1 xab1
Mais ce que je dois faire est de changer dynamiquement plusieurs de ces fichiers et je ne connais pas les noms de fichiers. Je veux écrire une commande qui lira tous les fichiers du répertoire courant en commençant par xa*
et sed
devrait changer le contenu du fichier.
sed -i 's/abc/xyz/g' xa*
?Réponses:
Mieux encore:
car personne ne sait combien de fichiers il y a, et il est facile de dépasser les limites de la ligne de commande.
Voici ce qui se passe lorsqu'il y a trop de fichiers:
la source
for
commande. Pour vous protéger de cela, vous devez utiliserfind ... | xargs ...
for
pourecho
ou pour ougrep
?"$i"
au lieu de$i
pour éviter le fractionnement de mots sur les noms de fichiers avec des espaces. Sinon c'est très sympa.for
fait partie de la syntaxe du langage, pas même simplement une fonction intégrée. Carsed -i 's/old/new' *
, l'expansion de*
doit ALL être passée en tant qu'arglist à sed, et je suis à peu près sûr que cela doit se produire avant même que lesed
processus puisse être lancé. En utilisant lafor
boucle, l'arglist complet (l'expansion de*
) n'est jamais passé en tant que commande, seulement stocké dans la mémoire du shell et itéré. Je n'ai aucune référence à ce sujet cependant, il semble juste que ce soit la différence. (J'adorerais entendre quelqu'un de plus compétent ...)Je suis surpris que personne n'ait mentionné l'argument -exec to find, qui est destiné à ce type de cas d'utilisation, bien qu'il lancera un processus pour chaque nom de fichier correspondant:
Alternativement, on pourrait utiliser xargs, qui invoquera moins de processus:
Ou plus simplement, utilisez la
+
variante exec au lieu de;
in find pour permettre à find de fournir plus d'un fichier par appel de sous-processus:la source
find ./ -type f -name 'xa*' -exec sed -i '' 's/asd/dsg/g' {} \;
c'est l'emplacement de la commande find./
et une paire de guillemets simples après-i
pour OSX../
est égale à.
et après-i
n'a que le paramètre backupsuffix.-exec
option de recherche avec{} +
est suffisante pour résoudre le problème comme indiqué et devrait convenir à la plupart des exigences. Maisxargs
c'est un meilleur choix en général car il permet également un traitement parallèle avec l'-p
option. Lorsque votre extension glob est suffisamment grande pour dépasser la longueur de votre ligne de commande, vous êtes susceptible de bénéficier également d'une accélération sur une exécution séquentielle.Vous pouvez utiliser grep et sed ensemble. Cela vous permet de rechercher des sous-répertoires de manière récursive.
la source
grep -v
pour éviter les dossiers gitgrep -rl <old> . | grep -v \.git | xargs sed -i 's/<old>/<new>/g'
Ces commandes ne fonctionneront pas par défaut
sed
avec Mac OS X.De
man 1 sed
:A essayé
et
Les deux fonctionnent bien.
la source
@PaulR a posté ceci comme un commentaire, mais les gens devraient le voir comme une réponse (et cette réponse convient le mieux à mes besoins):
Cela fonctionnera pour une quantité modérée de fichiers, probablement de l'ordre de dizaines, mais probablement pas de l'ordre de millions .
la source
sed -i 's|auth-user-pass nordvpn.txt|auth-user-pass /etc/openvpn/nordvpn.txt|g' *.ovpn
.Une autre façon plus polyvalente consiste à utiliser
find
:la source
J'utilise
find
pour une tâche similaire. C'est assez simple: vous devez le passer comme argument poursed
comme ceci:sed -i 's/EXPRESSION/REPLACEMENT/g' `find -name "FILE.REGEX"`
De cette façon, vous n'avez pas besoin d'écrire des boucles complexes, et il est simple de voir quels fichiers vous allez modifier, exécutez simplement
find
avant d'exécutersed
.la source
tu peux faire
' xxxx ' text u recherche et le remplacera par ' yyyy '
la source
Si vous êtes capable d'exécuter un script, voici ce que j'ai fait pour une situation similaire:
En utilisant un dictionnaire / hashMap (tableau associatif) et des variables pour la
sed
commande, nous pouvons parcourir le tableau pour remplacer plusieurs chaînes. L'inclusion d'un caractère générique dans lename_pattern
permettra de remplacer sur place dans les fichiers par un modèle (cela pourrait être quelque chose commename_pattern='File*.txt'
) dans un répertoire spécifique (source_dir
). Tous les changements sont écrits dans lelogfile
dans ledestin_dir
Tout d'abord, le tableau de paires est déclaré, chaque paire est une chaîne de remplacement, puis
WHAT1
sera remplacéeFOR1
etOTHER_string_to replace
sera remplacéestring replaced
dans le fichierFile.txt
. Dans la boucle le tableau est lu, le premier membre de la paire est récupéré en tant quereplace_what=$i
et le second en tant quereplace_for=$j
. Lafind
commande recherche dans le répertoire le nom de fichier (qui peut contenir un caractère générique) et lased -i
commande remplace dans le (s) même (s) fichier (s) ce qui a été précédemment défini. Enfin, j'ai ajouté ungrep
fichier redirigé vers le fichier journal pour enregistrer les modifications apportées au (x) fichier (s).Cela a fonctionné pour moi
GNU Bash 4.3
sed 4.2.2
et basé sur la réponse de VasyaNovikov pour Loop over tuples in bash .la source