Rechercher et remplacer du texte dans un fichier à l'aide de commandes

Réponses:

1053
sed -i 's/original/new/g' file.txt

Explication:

  • sed = Éditeur de flux
  • -i = in-situ (c.-à-d. sauvegarder dans le fichier d'origine)
  • La chaîne de commande:

    • s = la commande de substitution
    • original = une expression régulière décrivant le mot à remplacer (ou simplement le mot lui-même)
    • new = le texte pour le remplacer par
    • g = global (c'est-à-dire remplacer tout et pas seulement la première occurrence)
  • file.txt = le nom du fichier

cscarney
la source
3
@ Akiva Si vous incluez des caractères spéciaux regex dans votre recherche, ils sedseront identiques. Ajoutez un -rindicateur si vous souhaitez utiliser des RE étendues.
cscarney
32
@mcExchange S'il s'agit spécifiquement du /caractère que vous devez rechercher, vous pouvez simplement utiliser un autre caractère comme séparateur (par exemple 's_old/text_new/text_g'). Sinon, vous pouvez mettre un \ avant n'importe lequel $ * . [ \ ^pour obtenir le caractère littéral.
cscarney
3
@BrianZ En ce qui concerne le système de fichiers, la sortie de sed est un nouveau fichier portant le même nom. C'est l'un des bugs
cscarney
17
La commande OSX sed -i '.bak' 's/original/new/g' file.txtpeut également être exécutée avec une extension de longueur nulle sed -i '' 's/original/new/g' file.txt, qui ne générera aucune sauvegarde.
Kirk
20
Les utilisateurs MacOS devront ajouter '' "après -i en tant que paramètre pour -i ed.gs/2016/01/26/os-x-sed-invalid-command-code afin que le fichier soit écrasé.
geoyws
32

Il y a différentes façons de le faire. On utilise sedet Regex. SED est un éditeur de flux permettant de filtrer et de transformer du texte. Un exemple est le suivant:

marco@imacs-suck: ~$ echo "The slow brown unicorn jumped over the hyper sleeping dog" > orly
marco@imacs-suck: ~$ sed s/slow/quick/ < orly > yarly
marco@imacs-suck: ~$ cat yarly
The quick brown unicorn jumped over the hyper sleeping dog

Une autre façon qui peut faire plus de sens que < strinet > stroutest avec des tuyaux!

marco@imacs-suck: ~$ cat yarly | sed s/unicorn/fox/ | sed s/hyper/lazy/ > nowai
marco@imacs-suck: ~$ cat nowai 
The quick brown fox jumped over the lazy sleeping dog
Marco Ceppi
la source
6
notez que l' catin cat file | sed '...'est inutile. Vous pouvez directement dire sed '...' file.
fedorqui
1
En effet, ceci peut être réduit davantage: sed -i'.bak' -e 's/unicorn/fox/g;s/hyper/brown/g' yarlyle fichier sera gravé dans les yeux et fera les 2 changements en place tout en faisant une sauvegarde. Utilisant time bash -c "$COMMAND"le temps, cela suggère que cette version est environ 5 fois plus rapide.
pbhj
24

Il y a une multitude de façons de le réaliser. En fonction de la complexité de l'objectif recherché avec le remplacement de chaîne et des outils connus de l'utilisateur, certaines méthodes peuvent être préférées à d'autres.

Dans cette réponse, j'utilise un input.txtfichier simple , que vous pouvez utiliser pour tester tous les exemples fournis ici. Le contenu du fichier:

roses are red , violets are blue
This is an input.txt and this doesn't rhyme

FRAPPER

Bash n'est pas vraiment destiné au traitement de texte, mais des substitutions simples peuvent être effectuées via le développement de paramètres . Nous pouvons notamment utiliser ici une structure simple ${parameter/old_string/new_string}.

#!/bin/bash
while IFS= read -r line
do
    case "$line" in
       *blue*) printf "%s\n" "${line/blue/azure}" ;;
       *) printf "%s\n" "$line" ;;
    esac
done < input.txt

Ce petit script ne fait pas de remplacement sur place, ce qui signifie que vous devez enregistrer le nouveau texte dans un nouveau fichier et vous en débarrasser, ou mv new.txt old.txt

Note latérale: si vous êtes curieux de savoir pourquoi, while IFS= read -r ; do ... done < input.txton utilise le shell pour lire le fichier ligne par ligne. Voir ceci pour référence.

AWK

AWK, étant un utilitaire de traitement de texte, convient parfaitement à cette tâche. Il peut effectuer des remplacements simples et beaucoup plus avancés basés sur des expressions régulières . Il fournit deux fonctions: sub()et gsub(). Le premier ne remplace que la première occurrence, tandis que le second - remplace les occurrences dans la chaîne entière. Par exemple, si nous avons une chaîne one potato two potato, ce serait le résultat:

$ echo "one potato two potato" | awk '{gsub(/potato/,"banana")}1'
one banana two banana

$ echo "one potato two potato" | awk '{sub(/potato/,"banana")}1'                                      
one banana two potato 

AWK peut prendre un fichier d'entrée en argument, il input.txtserait donc facile de faire la même chose avec :

awk '{sub(/blue/,"azure")}1' input.txt

Selon la version d'AWK que vous possédez, il est possible que l'édition in-situ ne soit pas activée. Par conséquent, la pratique habituelle consiste à enregistrer et remplacer le nouveau texte. Par exemple, quelque chose comme ceci:

awk '{sub(/blue/,"azure")}1' input.txt > temp.txt && mv temp.txt input.txt

SED

Sed est un éditeur de ligne. Il utilise également des expressions régulières, mais pour de simples substitutions, il suffit de faire:

sed 's/blue/azure/' input.txt

Ce qui est bien avec cet outil, c'est qu'il dispose d'une édition sur place, que vous pouvez activer avec -iflag.

Perl

Perl est un autre outil souvent utilisé pour le traitement de texte, mais il s’agit d’un langage généraliste utilisé dans les réseaux, l’administration système, les applications de bureau, etc. Il a emprunté beaucoup de concepts / fonctionnalités d'autres langages tels que C, sed, awk et autres. La substitution simple peut être faite comme suit:

perl -pe 's/blue/azure/' input.txt

Comme sed, perl a également le drapeau -i.

Python

Ce langage est très polyvalent et est également utilisé dans une grande variété d'applications. Il a beaucoup de fonctions pour travailler avec des chaînes, parmi lesquelles replace(), donc si vous avez une variable comme var="Hello World", vous pourriez fairevar.replace("Hello","Good Morning")

Un moyen simple de lire le fichier et de remplacer la chaîne est le suivant:

python -c "import sys;lines=sys.stdin.read();print lines.replace('blue','azure')" < input.txt

Cependant, avec Python, vous devez également générer le nouveau fichier, ce que vous pouvez également créer à partir du script lui-même. Par exemple, voici un exemple simple:

#!/usr/bin/env python
import sys
import os
import tempfile

tmp=tempfile.mkstemp()

with open(sys.argv[1]) as fd1, open(tmp[1],'w') as fd2:
    for line in fd1:
        line = line.replace('blue','azure')
        fd2.write(line)

os.rename(tmp[1],sys.argv[1])

Ce script doit être appelé avec input.txtcomme argument de ligne de commande. La commande exacte pour exécuter un script python avec un argument de ligne de commande serait

 $ ./myscript.py input.txt

ou

$ python ./myscript.py input.txt

Bien sûr, assurez-vous qu'il se ./myscript.pytrouve dans votre répertoire de travail actuel et pour la première manière, assurez-vous qu'il est défini comme exécutable avecchmod +x ./myscript.py

Python peut aussi avoir des expressions régulières, en particulier le remodule, qui a une re.sub()fonction, qui peut être utilisé pour des remplacements plus avancés.

Sergiy Kolodyazhnyy
la source
1
Belle compilation! Une autre manière possible qui n’est pas mentionnée ici est d’utiliser la trcommande sous unix
Tapajit Dey
1
@TapajitDey Oui, tr c'est un autre excellent outil, mais notez qu'il sert à remplacer des ensembles de caractères (par exemple tr abc cde, traduirait apar c, ben d. C'est un peu différent de remplacer des mots entiers comme avec sedoupython
Sergiy Kolodyazhnyy Le
22

Vous pouvez utiliser Vim en mode Ex:

ex -s -c '%s/OLD/NEW/g|x' file
  1. % sélectionner toutes les lignes

  2. s remplacer

  3. g remplacer toutes les instances dans chaque ligne

  4. x écrire si des changements ont été faits (ils l'ont fait) et quitter

Steven Penny
la source
21

Grâce à la commande gsub de awk,

awk '{gsub(/pattern/,"replacement")}' file

Exemple:

awk '{gsub(/1/,"0");}' file

Dans l'exemple ci-dessus, tous les 1 sont remplacés par des 0 quelle que soit la colonne où ils se trouvent.


Si vous voulez remplacer une colonne en particulier, procédez comme suit:

awk '{gsub(/pattern/,"replacement",column_number)}' file

Exemple:

awk '{gsub(/1/,"0",$1);}' file

Il remplace 1 par 0 sur la première colonne uniquement.

À travers Perl,

$ echo 'foo' | perl -pe 's/foo/bar/g'
bar
Avinash Raj
la source
Je l'ai utilisé sur un terminal MacOS et il n'a rien fait ...
Jim
Testé sur Alpine Linux (dans le conteneur Docker) et aucune sortie
Salathiel Genèse
@ SalathielGenèse Qu'essayez-vous de réaliser?
Avinash Raj
Je fichier regarder avec inotifywaitsous shenv, et la communication des données au format CSV (car le format personnalisé est bogué). J'ai alors pensé qu'il n'y avait pas de moyen simple de gérer un document CSV dans des scripts shell ... Et je le veux très léger. J'ai donc lancé un script assez simple pour analyser et générer des rapports au format CSV. J'ai lu la spécification CSV et remarqué qu'elle est plus élaborée que prévu et que je prends en charge la valeur multiligne entre guillemets. Je sedcomptais sur la création de jetons, mais je me suis vite rendu compte que même les sedappels multilignes pouvaient comporter jusqu'à deux lignes. Que se passe-t-il alors si l'une de mes valeurs CSV s'étend sur plus de deux lignes?
Salathiel Genèse
Mieux vaut poser votre problème comme question.
Avinash Raj
8

sedest le s tream ed Itor dans la mesure où vous pouvez utiliser |(tuyau) pour envoyer des flux standard (STDIN et STDOUT spécifiquement) à travers sedet de les modifier par programme à la volée, ce qui en fait un outil pratique dans la tradition de la philosophie Unix; mais peut aussi éditer directement des fichiers en utilisant le -iparamètre mentionné ci-dessous.
Considérez ce qui suit :

sed -i -e 's/few/asd/g' hello.txt

s/est utilisé pour s ubstitute l'expression trouvée fewavec asd:

Les rares, les courageux.


Les asd, les braves.

/gsignifie "global", ce qui signifie le faire pour toute la ligne. Si vous laissez le champ /g(avec s/few/asd/, il doit toujours y avoir trois barres obliques quoi qu'il en soit) et fewapparaisse deux fois sur la même ligne, seul le premier fewest remplacé par asd:

Les rares hommes, les rares femmes, les braves.


Les hommes, les rares femmes, les braves.

Ceci est utile dans certaines circonstances, par exemple pour modifier des caractères spéciaux au début des lignes (par exemple, remplacer les symboles plus grands que certaines personnes utilisent pour citer les éléments précédents dans les fils de courrier électronique avec un onglet horizontal tout en laissant une inégalité algébrique citée plus tard dans la ligne. intacte), mais dans votre exemple où vous indiquez que n'importe où few se produit, il doit être remplacé, assurez-vous de l'avoir /g.

Les deux options suivantes (drapeaux) sont combinées en une seule -ie:

-ioption est utilisée pour modifier i placer n sur le fichier hello.txt.

-eoption indique la commande e xpression / à exécuter, dans ce cas s/.

Remarque: Il est important que vous utilisiez -i -epour rechercher / remplacer. Si vous le faites -ie, vous créez une sauvegarde de chaque fichier avec la lettre 'e' ajoutée.

Chaminda Bandara
la source
2

Vous pouvez faire comme ça:

locate <part of filaname to locate> | xargs sed -i -e "s/<Old text>/<new text>/g" 

Exemples: pour remplacer toutes les occurrences [logdir ',' '] (sans []) par [logdir', os.getcwd ()] dans tous les fichiers résultant de la commande de localisation, faites:

ex1:

locate tensorboard/program.py | xargs sed -i -e "s/old_text/NewText/g"

ex2:

locate tensorboard/program.py | xargs sed -i -e "s/logdir', ''/logdir', os.getcwd()/g"

où [tensorboard / program.py] est le fichier à rechercher

Nguyễn Tuấn Anh
la source
Salut. Votre choix de chaînes ( logdir', ''-> /logdir', os.getcwd()) rend cette réponse difficile à analyser. De plus, cela vaut la peine de préciser que votre réponse localise d’abord les fichiers à utiliser, car cela ne fait pas partie de la question.
mwfearnley
Bonjour, cette réponse permet à la fois de rechercher et de remplacer tout si elle a trouvé <ancien texte> dans le fichier.
Nguyễn Tuấn Anh
Je choisis cette réponse pour tout ce qu'ils utilisent tensorboard dans keras, qui veulent changer de commande de: tensorboard --logdir = '/ path / to / log / folder /' à utiliser: tensorboard uniquement, pour rester dans le dossier logs. c'est très pratique
Nguyễn Tuấn Anh