Remplacer une chaine de caractères dans plusieurs fichiers à la fois
Il existe plusieurs façons de remplacer une chaîne de caractères dans un ou plusieurs fichiers à la fois, selon votre environnement et vos outils. Voici les méthodes les plus courantes.
Les variantes , pour sed, awk et perl, avec des exemples clairs.
1. Insensible à la casse (chat, Chat, CHAT…)⚓︎
GNU sed⚓︎
sed -i.bak '0,/chat/I s/chat/chien/I' test2.txt
macOS (BSD sed)⚓︎
sed -i .bak '0,/chat/I s/chat/chien/I' test2.txt
I = ignore la casse (GNU + BSD)
awk '{ if (!done && sub(/chat/i, "chien")) done=1 } 1' test2.txt > tmp && mv tmp test2.txt
perl -i.bak -pe 's/chat/chien/i and $done=1 if !$done' test2.txt
2. Remplacer le mot entier seulement⚓︎
👉 évite que chaton ou tchat soient modifiés
sed -i.bak '0,/\bchat\b/s/\bchat\b/chien/' test2.txt
📌 \b = frontière de mot
awk '{ if (!done && sub(/\<chat\>/, "chien")) done=1 } 1' test2.txt > tmp && mv tmp test2.txt
perl -i.bak -pe 's/\bchat\b/chien/ and $done=1 if !$done' test2.txt
3. Mot entier + insensible à la casse (combo)⚓︎
sed -i.bak '0,/\bchat\b/I s/\bchat\b/chien/I' test2.txt
awk '{ if (!done && sub(/\<chat\>/i, "chien")) done=1 } 1' test2.txt > tmp && mv tmp test2.txt
perl -i.bak -pe 's/\bchat\b/chien/i and $done=1 if !$done' test2.txt
4. Sans modifier le fichier (sortie stdout seulement)⚓︎
sed '0,/chat/s/chat/chien/' test2.txt
awk '{ if (!done && sub(/chat/, "chien")) done=1 } 1' test2.txt
perl -pe 's/chat/chien/ and $done=1 if !$done' test2.txt
5. Tableau récapitulatif⚓︎
| Besoin | sed | awk | perl |
|---|---|---|---|
| Première occurrence fichier | ✔ | ✔ | ✔ |
| Insensible à la casse | ✔ | ✔ | ✔ |
| Mot entier | ✔ | ✔ | ✔ |
| Portable POSIX | ⚠️ | ✔ | ✔ |
| Le plus lisible | ⭐ | ⭐⭐ | ⭐⭐⭐ |
6. Remplacement dans plusieurs fichiers⚓︎
Dans la majorité des cas il suffit de mettre *.txt, mais il y a quelques points importants à connaître selon l’outil et le shell.
Cas simple : plusieurs fichiers .txt⚓︎
sed -i.bak '0,/chat/s/chat/chien/' *.txt
(avec fichier temporaire par fichier ❗)
for f in *.txt; do
awk '{ if (!done && sub(/chat/, "chien")) done=1 } 1' "$f" > "$f.tmp" && mv "$f.tmp" "$f"
done
perl -i.bak -pe 's/chat/chien/ and $done=1 if !$done' *.txt
📌 *.txt est développé par le shell (bash, zsh, etc.), pas par sed/perl/awk.
Point TRÈS IMPORTANT
La portée du “premier remplacement”
Que signifie première occurrence ?⚓︎
Il y a 2 comportements possibles :
Première occurrence par fichier (le plus courant)⚓︎
- sed : OK automatiquement
- awk : OK (variable
doneréinitialisée par fichier) - perl : ❌ PAS OK par défaut
En Perl, $done persiste entre fichiers
Perl — première occurrence dans chaque fichier⚓︎
perl -i.bak -pe '
BEGIN { $done=0 }
s/chat/chien/ and $done=1 if !$done;
close ARGV if eof
' *.txt
close ARGV if eof force Perl à réinitialiser les variables pour chaque fichier
Première occurrence globale sur tous les fichiers⚓︎
Un seul remplacement sur l’ensemble des fichiers⚓︎
perl (le plus simple)⚓︎
perl -i.bak -pe 's/chat/chien/ and $done=1 if !$done' *.txt
sed (possible mais moins lisible)⚓︎
sed -i.bak '0,/chat/s/chat/chien/' *.txt
7. Résumé rapide⚓︎
| Objectif | sed | awk | perl |
|---|---|---|---|
*.txt fonctionne |
✔ | ✔ | ✔ |
| 1ère occurrence par fichier | ✔ | ✔ | ⚠️ nécessite close ARGV |
| 1ère occurrence globale | ⚠️ | ⚠️ | ✔ |
| Backup automatique | ✔ | manuel | ✔ |
8. Bonnes pratiques⚓︎
Tester sans modifier⚓︎
Avec sed⚓︎
sed '0,/chat/s/chat/chien/' *.txt
Gérer les noms avec espaces⚓︎
for f in *.txt; do
sed -i.bak '0,/chat/s/chat/chien/' "$f"
done
Voici les méthodes propres pour afficher la liste des fichiers réellement modifiés, selon l’outil utilisé.
Avec sed (le plus simple)⚓︎
Afficher uniquement les fichiers où le remplacement a eu lieu⚓︎
sed -i.bak -n '0,/chat/{s/chat/chien/;p;w /dev/stdout}' *.txt
⚠️ Cette forme est un peu “acrobatique”. La méthode recommandée est plutôt 👇
Méthode fiable (portable)⚓︎
for f in *.txt; do
if sed '0,/chat/s/chat/chien/' "$f" | cmp -s "$f" -; then
: # pas de changement
else
echo "modifié : $f"
sed -i.bak '0,/chat/s/chat/chien/' "$f"
fi
done
Avec perl (recommandé)⚓︎
Afficher les fichiers modifiés (1ère occurrence par fichier)⚓︎
perl -i.bak -pe '
BEGIN { $done=0; $changed=0 }
if (s/chat/chien/ and !$done) { $done=1; $changed=1 }
close ARGV if eof and do {
print STDERR "modifié : $ARGV\n" if $changed;
$done=0; $changed=0;
}
' *.txt
📌 Sortie sur stderr, pour ne pas mélanger avec le contenu.
Avec awk⚓︎
for f in *.txt; do
if awk '{ if (!done && sub(/chat/, "chien")) done=1 } 1' "$f" | cmp -s "$f" -; then
:
else
echo "modifié : $f"
awk '{ if (!done && sub(/chat/, "chien")) done=1 } 1' "$f" > "$f.tmp" && mv "$f.tmp" "$f"
fi
done
La solution la plus simple et robuste⚓︎
Perl en une seule commande, avec affichage clair :
perl -i.bak -pe '
if (s/chat/chien/ and !$done) { $done=1; $changed=1 }
close ARGV if eof and do {
print STDERR "$ARGV\n" if $changed;
$done=0; $changed=0;
}
' *.txt
Sortie:
fichier1.txt
fichier3.txt
Astuce bonus⚓︎
Voir ce qui va changer avant modification⚓︎
perl -pe 's/chat/chien/ and $done=1 if !$done' *.txt | diff -u *.txt -
(ou version simplifiée sur un seul fichier)
Voici une solution complète “clé en main” qui fait tout en une fois :
- traitement récursif
- remplacement première occurrence par fichier
- affichage des fichiers modifiés
- affichage ancienne → nouvelle ligne
- génération d’un log
- création d’un backup
Le tout avec Perl + find, robuste et lisible.
Solution complète recommandée⚓︎
find . -type f -name "*.txt" -exec perl -i.bak -pe '
if (!$done && s/chat/chien/) {
$done=1;
$changed=1;
print STDERR " $ARGV : $& → chien\n";
}
close ARGV if eof and do {
print STDERR "modifié : $ARGV\n" if $changed;
print LOG "modifié : $ARGV\n" if $changed;
$done=0;
$changed=0;
}
' {} + 2> modifications.log
Ce que fait exactement cette commande⚓︎
Récursivement⚓︎
find . -type f -name "*.txt"
.txt dans l’arborescence
Remplacement⚓︎
s/chat/chien/
Réinitialisation par fichier⚓︎
close ARGV if eof
Affichage en direct (stderr)⚓︎
modifié : ./docs/a.txt
./docs/a.txt : chat → chien
Log automatique⚓︎
modifications.log
Contenu:
modifié : ./docs/a.txt
modifié : ./notes/b.txt
Backup⚓︎
fichier.txt.bak
Exemple de sortie⚓︎
modifié : ./test1.txt
./test1.txt : chat → chien
modifié : ./subdir/test3.txt
./subdir/test3.txt : chat → chien
Variantes utiles⚓︎
Insensible à la casse⚓︎
s/chat/chien/i
Mot entier uniquement⚓︎
s/\bchat\b/chien/
Mot entier + insensible à la casse⚓︎
s/\bchat\b/chien/i
Sans modification (dry-run)⚓︎
find . -name "*.txt" -exec perl -pe 's/chat/chien/ and $done=1 if !$done' {} +
9. Résumé final⚓︎
| Fonction | OK |
|---|---|
| Récursif | ✔ |
| 1ʳᵉ occurrence / fichier | ✔ |
| Affiche fichiers modifiés | ✔ |
| Affiche ancien → nouveau | ✔ |
| Log | ✔ |
| Backup | ✔ |
10. Suppression d'un mot avec expression régulière⚓︎
Fichier de départ:
date: '2026-01-20 12:00:00'
date: '2026-01-20 12:00:00'
date: '2026-01-20 12:00:00'
date: '2026-01-20 12:00:00'
date: '2026-01-20 12:00:00'
Sans modification, uniquement en mémoire
sed "0,/date: '\([0-9-]\{10\}\) [0-9:]\{8\}'/s//date: '\1'/" test.txt
Résultat:
date: '2026-01-20'
date: '2026-01-20 12:00:00'
date: '2026-01-20 12:00:00'
date: '2026-01-20 12:00:00'
date: '2026-01-20 12:00:00'
date: '2026-01-20 12:00:00'
Avec perl sur un fichier⚓︎
perl -i -pe '
if (!$done && s/date: '\''([0-9-]{10}) [0-9:]{8}'\''/date: '\''$1'\''/) {
$done = 1;
}
' test.txt
Avec perl sur plusieurs fichiers⚓︎
find . -type f -name "*.txt" -exec perl -pe '
if (!$done && s/date: '\''([0-9-]{10}) [0-9:]{8}'\''/date: '\''$1'\''/) {
$done=1;
$changed=1;
print STDERR " $ARGV : $& → $1\n";
}
close ARGV if eof and do {
print STDERR "modifié : $ARGV\n" if $changed;
print LOG "modifié : $ARGV\n" if $changed;
$done=0;
$changed=0;
}
' {} + 2> modifications.log