Le remplacement de chaînes dans des fichiers en fonction de certains critères de recherche est une tâche très courante. Comment puis-je
- remplacer la chaîne
foo
parbar
dans tous les fichiers du répertoire actuel? - faire de même récursivement pour les sous-répertoires?
- remplacer uniquement si le nom du fichier correspond à une autre chaîne?
- remplacer uniquement si la chaîne est trouvée dans un certain contexte?
- remplacer si la chaîne est sur un certain numéro de ligne?
- remplacer plusieurs chaînes avec le même remplacement
- remplacer plusieurs chaînes avec différents remplacements
text-processing
awk
sed
perl
terdon
la source
la source
Réponses:
1. Remplacer toutes les occurrences d’une chaîne par une autre dans tous les fichiers du répertoire en cours:
Il s’agit des cas où vous savez que le répertoire ne contient que des fichiers normaux et que vous souhaitez traiter tous les fichiers non cachés. Si ce n'est pas le cas, utilisez les approches de 2.
Toutes les
sed
solutions dans cette réponse supposent GNUsed
. Si vous utilisez FreeBSD ou OS / X, remplacez-i
par-i ''
. Notez également que l'utilisation du-i
commutateur avec toute version desed
a des implications sur la sécurité du système de fichiers et est déconseillée dans les scripts que vous envisagez de distribuer de quelque manière que ce soit.Non récursif, fichiers dans ce répertoire uniquement:
(
perl
celui-ci échouera pour les noms de fichiers se terminant par|
ou espace) ).Fichiers récursifs ordinaires ( y compris ceux cachés ) dans ce sous-répertoire et dans tous les sous-répertoires
Si vous utilisez zsh:
(peut échouer si la liste est trop grande, voir
zargs
pour contourner le problème).Bash ne peut pas rechercher directement les fichiers normaux, une boucle est nécessaire (les accolades évitent de définir les options globalement):
Les fichiers sont sélectionnés lorsqu'il s'agit de fichiers réels (-f) et qu'ils sont accessibles en écriture (-w).
2. Ne remplacez que si le nom du fichier correspond à une autre chaîne / a une extension spécifique / est d'un certain type, etc.:
Non récursifs, les fichiers de ce répertoire uniquement:
Fichiers récursifs et réguliers dans ce sous-répertoire et dans tous les sous-répertoires
Si vous utilisez bash (les accolades évitent de définir les options globalement):
Si vous utilisez zsh:
Le
--
signesed
que plus aucun drapeau ne sera donné dans la ligne de commande. Ceci est utile pour se protéger contre les noms de fichiers commençant par-
.Si un fichier est d'un certain type, par exemple, exécutable (voir
man find
pour plus d'options):zsh
:3. Ne remplacez que si la chaîne est trouvée dans un certain contexte
Remplacez
foo
parbar
seulement s'il y a unbaz
dernier sur la même ligne:Dans
sed
, utilisez\( \)
enregistre tout ce qui est entre parenthèses et vous pouvez y accéder avec\1
. Il existe de nombreuses variantes de ce thème. Pour en savoir plus sur ces expressions régulières, voir ici .Remplacer
foo
parbar
seulement sifoo
est trouvé sur la colonne 3d (champ) du fichier d'entrée (en supposant que les champs sont séparés par des espaces):(nécessite
gawk
4.1.0 ou plus récent).Pour un champ différent, utilisez simplement
$N
oùN
est le numéro du champ d’intérêt. Pour un séparateur de champ différent (:
dans cet exemple), utilisez:Une autre solution utilisant
perl
:REMARQUE: les solutions
awk
etperl
affecteront les espaces dans le fichier (supprimez les espaces de début et de fin et convertissez les séquences d'éléments en un caractère d'espacement dans les lignes correspondantes). Pour un champ différent, utilisez$F[N-1]
oùN
est le numéro de champ souhaité et pour un séparateur de champ différent, utilisez ($"=":"
définit le séparateur de champ en sortie sur:
):Remplacez
foo
parbar
seulement sur la 4ème ligne:4. Plusieurs opérations de remplacement: remplacez par différentes chaînes
Vous pouvez combiner des
sed
commandes:Sachez que l'ordre compte (
sed 's/foo/bar/g; s/bar/baz/g'
sera substituéfoo
parbaz
).ou commandes Perl
Si vous avez un grand nombre de patterns, il est plus facile de sauvegarder vos patterns et leurs remplacements dans un
sed
fichier de script:Ou, si vous avez trop de paires de modèles pour que ce qui précède soit réalisable, vous pouvez lire les paires de modèles à partir d'un fichier (deux modèles séparés par des espaces, $ pattern et $ replacement, par ligne):
Cela sera assez lent pour les longues listes de modèles et les fichiers de données volumineux. Vous voudrez peut-être lire les modèles et en créer un
sed
script à la place. Ce qui suit suppose qu'un délimiteur <space> sépare une liste de paires MATCH <space> REPLACE se produisant une par ligne dans le fichierpatterns.txt
:Le format ci-dessus est largement arbitraire et, par exemple, ne permet pas un <espace> dans MATCH ou REPLACE . La méthode est cependant très générale: si vous pouvez créer un flux de sortie qui ressemble à un
sed
script, vous pouvez le générer en tant quesed
script en spécifiantsed
le fichier de script-
stdin.Vous pouvez combiner et concaténer plusieurs scripts de la même manière:
Un POSIX
sed
concaténera tous les scripts en un seul dans l’ordre dans lequel ils apparaissent sur la ligne de commande. Aucune de ces\n
choses ne doit se terminer par une ewline.grep
peut fonctionner de la même manière:Lorsque vous utilisez des modèles de chaînes fixes, il est recommandé d'échapper aux métacaractères d' expression régulière . Vous pouvez le faire assez facilement:
5. Plusieurs opérations de remplacement: remplacez plusieurs modèles avec la même chaîne
Remplacez l' une des
foo
,bar
oubaz
avecfoobar
ou
la source
zsh
. Bien sûr, ajoutez deszsh
informations, mais il n’ya aucune raison de supprimer les éléments bash. De plus, je sais que l’utilisation du shell pour le traitement de texte n’est pas idéale, mais il existe des cas où cela est nécessaire. J'ai édité dans une meilleure version de mon script original qui créera unsed
script au lieu d'utiliser réellement la boucle du shell pour analyser. Cela peut être utile si vous avez plusieurs centaines de paires de motifs par exemple.(.)
qualificatif globbing, il ne peut donc pas être utilisé ici. (vous en manquez - aussi). La boucle for est incorrecte (-r) et signifie qu'il faut effectuer plusieurs passes dans les fichiers sans aucun avantage par rapport à un script sed.--
aprèssed -i
et avant la commande de substitution?-
. Son utilisation garantit que les commandes fonctionneront sur des fichiers portant des noms tels que-foo
. Sans cela, le-f
serait analysé comme une option..git
répertoire et gâcheront votre commande. Mieux vaut opérer dans / sur des répertoires spécifiques par leur nom.Une bonne r e pl acement outil Linux est RPL , qui a été écrite à l' origine pour le projet Debian, il est disponible avec
apt-get install rpl
dans toute distro dérivée de Debian, et peut - être pour d' autres, mais sinon , vous pouvez télécharger letar.gz
fichier SourgeForge .Exemple d'utilisation le plus simple:
Notez que si la chaîne contient des espaces, elle doit être placée entre guillemets. Par défaut ,
rpl
prendre soin des lettres majuscules , mais pas de mots complets , mais vous pouvez modifier ces valeurs par défaut avec des options-i
(ignorer la casse) et-w
(mots entiers). Vous pouvez également spécifier plusieurs fichiers :Ou même spécifier les extensions (
-x
) pour rechercher ou même rechercher récursivement (-R
) dans le répertoire:Vous pouvez également rechercher / remplacer en mode interactif avec
-p
l'option (invite):La sortie indique le nombre de fichiers / chaîne remplacés et le type de recherche (casse dans / sensible, mots entiers / partiels), mais il peut être silencieux avec l’ option
-q
( mode silencieux ), ou même plus détaillée, énumérant les numéros de ligne contenant correspondances de chaque fichier et répertoire avec option-v
( mode détaillé ).D' autres options qui sont à retenir sont
-e
( l' honneur e hampes) qui permettentregular expressions
, vous pouvez rechercher également des onglets (\t
), de nouvelles lignes (\n
), etc. Même vous pouvez utiliser-f
pour forcer les autorisations (bien sûr, uniquement lorsque l'utilisateur dispose d'autorisations en écriture) et-d
pour conserver les temps de modification`).Enfin, si vous ne savez pas exactement ce que vous ferez, utilisez le mode
-s
( simuler ).la source
Comment faire une recherche et remplacer sur plusieurs fichiers suggère:
Mes meilleurs résultats proviennent de l'utilisation de perl et de grep (pour garantir que le fichier contient l'expression de recherche)
la source
Vous pouvez utiliser Vim en mode Ex:
la source
J'ai utilisé ceci:
Répertorie tous les fichiers qui contiennent
old_string
.Remplacez nouvelle ligne dans le résultat par des espaces (afin que la liste des fichiers puisse être alimentée)
sed
.Exécuter
sed
sur ces fichiers pour remplacer l’ancienne chaîne par la nouvelle.Mise à jour: le résultat ci-dessus échouera pour les noms de fichiers contenant des espaces. Au lieu de cela, utilisez:
grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'
la source
grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'
le fera traiter avec des noms de fichiers arbitraires.Du point de vue de l'utilisateur, c'est un outil Unix simple et agréable qui fait le travail à la perfection
qsubst
. Par exemple,remplacera
foo
parbar
dans tous mes fichiers C. Une fonctionnalité intéressante consiste àqsubst
faire une requête de remplacement , c'est -à- dire qu'elle me montrera chaque occurrence defoo
et me demandera si je veux la remplacer ou non. [Vous pouvez remplacer sans condition (pas demander) avec-go
option, et il existe d'autres options, par exemple,-w
si vous souhaitez uniquement remplacerfoo
lorsqu'il s'agit d'un mot entier.]Comment l'obtenir: a
qsubst
été inventé par der Mouse (de McGill) et envoyé à comp.unix.sources 11 (7) en août 1987. Des versions mises à jour existent. Par exemple, la version de NetBSD estqsubst.c,v 1.8 2004/11/01
compilée et fonctionne parfaitement sur mon mac.la source
J'avais besoin de quelque chose qui fournirait une option sèche et fonctionnerait de manière récursive avec un glob, et après avoir essayé de le faire avec
awk
,sed
j'ai abandonné et je l'ai fait à la place en python.Le script recherche récursivement tous les fichiers correspondant à un motif global (par exemple
--glob="*.html"
) et les remplace par les expressions régulières de remplacement:Chaque option longue telle qu’elle
--search-regex
a une option courte correspondante, c.-à-d-s
. Exécuter avec-h
pour voir toutes les options.Par exemple, cela retournera toutes les dates de
2017-12-31
à31-12-2017
:la source
globstar
option et les**
globs ou les options de bash (ou l'équivalent de votre shell)find
. Pour un essai à sec, utilisez simplementsed
. À moins que vous n'utilisiez cette-i
option, aucune modification ne sera apportée. Pour une sauvegarde, utilisezsed -i.bak
(ouperl -i .bak
); pour les fichiers qui ne correspondent pas, utilisezgrep PATTERN file || echo file
. Et pourquoi dans le monde voudriez-vous que Python étende le glob au lieu de laisser le shell le faire? Pourquoiscript.py --glob=foo*
au lieu de justescript.py foo*
?sed
etawk
bien et être peu disposés à investir du temps supplémentaire sur les maîtriser, (4) la lisibilité, (5) cette solution travaillera également sur les systèmes non-posix (pas que j'en ai besoin, mais quelqu'un d'autre pourrait)ripgrep (nom de la commande
rg
) est ungrep
outil, mais prend également en charge la recherche et le remplacement.rg
ne prend pas en charge l'option sur place, vous devrez donc le faire vous-mêmeConsultez la documentation de Rust regex pour connaître la syntaxe et les fonctionnalités des expressions régulières. Le
-P
commutateur activera la version PCRE2 .rg
prend en charge Unicode par défaut.De même
grep
, l'-F
option permettra aux chaînes fixes de correspondre, une option pratique que je pensesed
devoir également implémenter.Une autre option pratique consiste à
-U
activer la correspondance multiligne.rg
peut aussi gérer des fichiers de type dosUn autre avantage
rg
est qu'il est susceptible d'être plus rapide quesed
la source