Aller au contenu

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 done ré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"
→ tous les .txt dans l’arborescence

Remplacement⚓︎

s/chat/chien/
première occurrence seulement par fichier

Réinitialisation par fichier⚓︎

close ARGV if eof
→ indispensable pour Perl sur plusieurs fichiers

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