Remplacer un chaine de caractère avec la commande sed
Voici une petite astuce bien pratique qui permet de changer une chaîne de caractères par une autre, contenue dans un fichier texte. Tout ceci se réalise en une seule ligne de commande, grâce à sed.
Voici un exemple d'utilisation :
sed -i -e "s/chaines1/chaine2/g" fichier
A noter que si la chaîne contient des caractères spéciaux, on devra les échapper avec '\'. Voici un exemple oû l'on remplace "/home" par "/tmp" :
sed -i -e "s/\/home/\/tmp/g" fichier
Si on a besoin de remplacer une chaîne par une autre pour toute une liste de fichiers contenue dans un répertoire, on pourra utiliser ce petit script basé sur le même principe :
#!/bin/bash
for file in *.txt
do
echo "Traitement de $file ..."
sed -i -e "s/chaine1/chaine2/g" "$file"
done
Ce dernier va :
1. établir la liste de tous les fichiers dont l'extension est .txt
2. puis effectuer le remplacement
Edit : une autre méthode donnée en commentaire qui utilise la commande find et qui permet de traiter des sous-dossier en plus :
find . -name "*.txt" -type f -exec sed -i "s/chaine1/chaine2/g" {} \;
36 Commentaires pour "Remplacer un chaine de caractère avec la commande sed"
Flux des commentaires de cet article Ajouter un commentaire@Laurent Rineau : merci pour l'info, c'est vrai que dans le cas du script qui peut modifier énormément de fichiers, cela peut être très utile. Je modifie mes commandes.
Si tu utilises GNU/sed, tu peux utiliser l'option -i pour te faciliter la vie. Ton premier exemple se transforme en :
sed -i -e "s/chaines1/chaine2/g" fichier
et ton deuxième exemple, le script bash, se transforme en :
sed -i -e "s/chaine1/chaine2/g" *.txt
Si tu mets un truc après l'option -i, sed crée des backups. Exemple :
sed -i.bak -e "s/chaine1/chaine2/g" *.txt
va modifier tous les *.txt et va créer des backups *.txt.bak.
Au-lieu de "for ...", find peut être plus élégant.
find . -name "*.txt" [+ plein de conditions] -exec cp -p {} {}.orig \; -exec sed -i "s/tralala/trilili/g" {} \;
Le premier "-exec" fait une copy.
@moi :
Moi je préfère largement utiliser les boucles for du shell que find. Notamment avec le shell Zsh le glob permet d'avoir n'importe quelle condition, comme find et même plus.
1/ Ta notion « d'élégant » est très douteuse.
2/ Tu n'as pas lu ce que j'ai écris : ta copie est inutile, avec une option "-i.orig" à sed.
A note r: Plutôt que protéger le caractère / car vous utilisez le caractère / comme séparateur, utilisez plutôt le caractère #
Exemple :
sed -e "s/\/home/\/tmp/g" fichier > fichier.tmp && mv -f fichier.tmp fichier
Plus facile :
sed -e "s#/home#/tmp#g" fichier > fichier.tmp && mv -f fichier.tmp fichier
Ca peut sauver la vie dans des scripts
@moi : c'est vrai que je n'avais pas pensé au find.
Mais l'avantage du script est que l'on peux facilement rajouter d'autres opérations. Maintenant find à l'avantage de traiter les sous-repertoires de façon bien plus simple.
@krusaf : c'est noté.
C'est clair que pour le coup un for est largement plus clair que find. Find vaut le coup quand les fichiers à modifier sont plus difficiles à retrouver.
Par contre, pense à utiliser les guillemets doubles pour les noms de fichiers ("$file") au cas où tu tombes sur des noms avec des espaces...
@liberforce : j'ai fait la modification du script afin d'ajouter les guillemets.
J'avais écrit un billet sur le sujet: blog.nicolargo.com/2007/0...
La méthode utilisait Perl:
# find ./ -type f | xargs perl -pi -w -e 's/titi/tata/g'
a+
Pour Nicolargo
Préfères :
$ find ... -print0 | xargs -0 ....
Ainsi les noms de fichiers qui ont un retour chariot ne posent pas de problème.
Tiens au fait, j'avais fait un 'ti post sur les expressions régulières avec "sed" en exemple.
Si ça t'intéresse : temet79.free.fr/index.php...
(désolé pour le lien à rallonge)
@Nicolargo, @moi, @Temet : merci pour les infos.
Y a pas a dire, le bash c'est vraiment util :).
Si l'on veut faire une modification dans plusieurs fichiers qui sont dans plusieurs répertoires,
est ce qu'un "for file in */*.txt" peut fonctionner ?
merci
@scraly : en mettant */*.txt tu ne traitera que les fichier txt contenu dans des sous-répertoire. les fichiers dans le répertoire courant, tous ceux contenu dans des sous-sous-répertoire ne seront pas pris en compte.
Bonjour,
J'ai une petite question... Si quelqu'un peut m'aider ça serait cool
Je voudrai modifier des caractéres dans une chaine de caractére, sachant qu'elle est contenu dans une variable. Est-ce que "sed" peut le faire?
Je vous pose mon problème... En fait j'ai un format de date qui est le suivant:
date=2008Fev22 (22 Fevrier 2008). Et je voudrai remplacer le Fev par un 02. Peut-on avec sed, spécifier la variable "date" pour que la modification se fasse que sur la variable et non sur un fichier???
Merci pour vos réponse
Mus
@Muss : essaye comme ceci :
ma variable date=`grep EMS /var/adm/syslog/syslog.log | awk '{print $1 $2 $3}'`
echo $date
==> 2008Fev22
je voudrai une commande qui puisse chnager le "Fev" en "02" juste en spécifiant la variable...
Merci pour votre aide
J'ai essaye ce script. Mais ça ne me donne rien. Aucun fichier n'est modifie.
Bonjour,
je souhaiterai modifier une chaine de caractere dans plusieurs fichier mais mon problème est que ce remplacement de chaîne de caractère est different d'un fichier à un autre.
J'ai pensé mettre trois colonne dans un fichier exel : la premiere contiendrait la liste des fichier à midifier la deuxième la chaine de caractère à remplacer et enfin la troisième la nouvelle chaine de caractère.
quelqu'un aurait une petite idée?
Merci :o)
@liza74 : Pour chaque fichier voulus tu fais ta modif en combinant sed a find :
find . -name monfichier -type f --exec sed -i -e 's/$FIND/$REPLACE/g' {}
nickel merci ! tes collègues chez qui je suis tombé n'expliquaient pas comment échapper les car spéciaux.
@Muss : La meilleur et simple facon de modifier la date en linux est la suivante:
#date 022215302008
avec: 02 representant le mois
22 representant le jour
1530 representant l'heure et les minutes
2008 representant l'annee
Bonjour svp quelqu'un pulse m'aider !!!
je veux fair un script que je lui passe en parameter un nom et qu'il efface un # qui se trouve au début de cette ligne qui contient ce nom
@hamza : si tu espéres encore une réponse ou pour d'autres qui réinterrogeraient de savoir comment faire:
echo "### tomy"| sed -e "s/^##* *//"
Fonctionne quelque-soit le nombre de # et supprime les éventuels espaces devant le nom.
merci bqq cv j'ai passé cette etape mtn je veux supprimer une chaine dans un fichier sans supprimer tous le contenue de fichier
echo "### début-chaîne-à-supprimer-fin le reste de mon fichier" > fichier.txt
sed -i "s/début.*fin//" fichier.txt
ou supprimer simplement le mot chaîne du fichier.txt:
sed -i "s/chaîne//" fichier.txt
non c pas je veux supprimer une chaine dans un fichier cfg
la chaine est variable que je la passe en parametre dans un script shell sous php !!
shell_exet("script.sh".$chaine);
mon prob que le script ne connais jamais la chaine par contre si je fait un echo avan just shell-exec je vois ma chaine
script.sh:
#!/bin/bash
sed -i "s/$1//" fichier.cfg
shell_exec('sh script.sh ' . $chaine)
ouiii c bien exatement ca !! mon probleme que le script ne connais pas mon variable($chaine)!!
j'ai vu au log (not found)!!!!je comprend pas pk
Bonjour,
Dans mon cas, je veux remplacer crocher "[" par un blanc, voici ma syntaxe : sed s'/[//g' , mais ca me donne l'erreur suivante : sed: -e expression #1, char 6: unterminated `s' command.
Merci
Bonjour,
J'utilise un script dans ce genre :
find . -name "*.php" -type f -exec sed -i "s/chaine1/chaine2/g" {} \;
Le problème est que tous mes fichiers php voient leur date modifiée, même s'ils ne sont pas concernés par le remplacement, ce qui est problématique pour moi. Qui connaîtrait le moyen de ne modifier que les fichiers concernés par la substitution ?
Bonjour je souhaite modifier le nom d'une série de fichiers à la fois
exemple fichier:
RH_A_142_2_timestamp.dat
RH_B_142_2_timestamp.dat
RH_C_142_2_timestamp.dat
etc...
je souhaite enlever le 142_2 de tous mes fichiers ?
donc avoir :
RH_A_timestamp.dat
RH_B_timestamp.dat
RH_C_timestamp.dat
pourriez vous m'aider à trouver une expression simple ??
merci
Bonjour knock ,
sed -i 's/RH_A_142_2_timestamp.dat/RH_A_timestamp.dat/g'
le meme pour b et c
Cordialement;
Salut,
Je voudrais ajouter une ligne en fin de fichier à une série de pages web nommées mesfichiers.md.html (c'est du markdown mélioré), j'ai utilisé la commande suivante:
find . -name "*.md.html" -type f -exec sed -e '$a\la ligne à ajouter ' {} \;
Le terminal affiche bien la modif dans mes fichiers mais elle n'est pas réalisée dans mes fichiers !!!
Si vous pouvez m'aider
Cordialement
Bonjour,
Moi je voudrais changer un fichier csv de mon stock pour le rendre compatible avec ma base de mon CMS.
Le problème je bloque sur cela :
sed -i -e "s/\749/\MONTRES HOMME/g" $OUT
Il me fait une erreur quand je recherche des chiffres?
sed: 1: "s/\749/\MONTRES HOMME/g": RE error: invalid backreference number
Alors que quand c'est des lettres pas de problème.
J'ai essayé d'entourer avec des ' " () rien a faire, une idée?
Google m'a pas aidé sur le coup là
MErci