Linux / Commande diff : comparer des fichiers texte et des dossiers

La commande GNU diff compare des fichiers texte ligne par ligne et montre ce qui doit changer pour passer du premier au second. Avec diff -u, les lignes retirées, ajoutées et leur contexte apparaissent dans un format facile à relire ou à enregistrer comme correctif. Son code de sortie 1 signifie que des différences ont été trouvées ; 2 signale un problème.

Les exemples ci-dessous créent de petits fichiers dans un dossier de pratique. Ils suivent le manuel GNU de diff et sa liste officielle des options. Sur votre machine, consultez diff --help pour vérifier les options réellement installées.

Préparer deux fichiers et lire une différence unifiée

Dans la syntaxe diff [OPTION]... ANCIEN NOUVEAU, l'ordre est essentiel : le résultat décrit le passage du premier fichier au second. Un tiret seul désigne l'entrée standard. Pour un nom de fichier commençant par un tiret, utilisez le séparateur d'options --.

Créez un dossier temporaire appartenant à votre compte, puis deux versions d'un même réglage :

lab=$(mktemp -d "$HOME/diff-lab.XXXXXX") || exit 1
printf 'mode=dev\nport=8080\nlog=on\n' > "$lab/ancien.conf"
printf 'mode=prod\nport=8080\nlog=on\n' > "$lab/nouveau.conf"
diff -u -- "$lab/ancien.conf" "$lab/nouveau.conf"
status=$?
printf 'Code de comparaison : %s\n' "$status"

Le résultat contient des lignes d'en-tête --- et +++ avec les chemins et des horodatages, puis un bloc commençant par @@. Sa partie utile pour cet exemple est :

-mode=dev
+mode=prod

Le signe - retire une ligne du premier fichier, + ajoute une ligne du second et l'espace conserve une ligne de contexte. Le code affiché doit être 1. Les en-têtes et les nombres du bloc dépendent des chemins, des dates et du contexte choisi ; ne comparez pas toute cette sortie comme une chaîne figée.

Interpréter les codes de sortie dans un script

Code Signification GNU diff Décision
0 Aucune différence trouvée. Les entrées comparées sont égales selon les options choisies.
1 Une différence a été trouvée. Examiner ou traiter le changement attendu.
2 La comparaison a rencontré un problème. Lire le diagnostic et corriger l'entrée ou l'accès.

Une sortie vide n'est donc une preuve d'égalité que si la commande s'est terminée avec 0. L'option -q limite le détail affiché, mais ne change pas le sens des codes. Un fichier absent, par exemple, ne doit pas être classé comme une simple différence de contenu :

if diff -q -- "$lab/ancien.conf" "$lab/nouveau.conf"; then
  printf 'Aucune différence\n'
else
  status=$?
  if test "$status" -eq 1; then
    printf 'Contenus différents\n'
  else
    printf 'Comparaison impossible : code %s\n' "$status" >&2
  fi
fi

Avec les fichiers créés plus haut, le message « Contenus différents » est attendu. Si vous remplacez le second chemin par un fichier inexistant, c'est la branche d'erreur qui doit être choisie. Dans un script lancé avec set -e, placez une comparaison qui peut légitimement renvoyer 1 dans une condition comme ci-dessus : une commande diff isolée pourrait interrompre le script avant l'examen du résultat.

Comparer des dossiers sans confondre contenu et arborescence

Deux noms de dossiers en arguments comparent les fichiers correspondants ; -r descend aussi dans leurs sous-dossiers. -q donne un rapport bref, tandis que -u affiche les différences de lignes des fichiers texte. Les chemins présents d'un seul côté sont signalés, mais diff ne vérifie pas à lui seul les propriétaires, permissions ou dates.

mkdir -p -- "$lab/version-a/conf" "$lab/version-b/conf"
printf 'debug=on\n' > "$lab/version-a/conf/app.conf"
printf 'debug=off\n' > "$lab/version-b/conf/app.conf"
printf 'ancien\n' > "$lab/version-a/obsolete.txt"
diff -qr -- "$lab/version-a" "$lab/version-b"
status=$?
printf 'Code de comparaison : %s\n' "$status"

Le rapport bref doit mentionner conf/app.conf comme différent et obsolete.txt comme présent uniquement dans version-a ; le code est 1. Pour voir précisément la modification du fichier de configuration, remplacez -q par -u en conservant -r. Sur une arborescence réelle, vérifiez d'abord les répertoires choisis et leur contenu attendu : un dossier de sauvegarde peut contenir des fichiers supplémentaires légitimes.

Choisir les options selon la question posée

Option Effet Point de vigilance
-u Affiche le format unifié avec trois lignes de contexte par défaut. Le sens des signes dépend de l'ordre des deux fichiers.
-r Descend dans les sous-dossiers correspondants. Peut produire une longue sortie ; choisir d'abord deux racines précises.
-q Indique seulement quels fichiers diffèrent. Ne montre pas les lignes à corriger.
-s Signale aussi les fichiers identiques. Peut encombrer le rapport d'une grande arborescence.
-b Ignore les changements de quantité d'espaces et tabulations. Peut masquer une différence utile.
-w Ignore les blancs lors de la comparaison des lignes. Ne convient pas si l'espacement porte du sens.
-i Ignore la différence entre majuscules et minuscules. Inadapté aux identifiants sensibles à la casse.
--color=auto Colore les différences quand la sortie est un terminal compatible. La sortie redirigée n'est normalement pas colorée.

Pour une comparaison qui doit respecter exactement les octets, n'utilisez pas les options d'ignorance. Dans du code Python, YAML ou des configurations où l'indentation a un sens, -b et -w peuvent cacher un changement fonctionnel. Un exemple contrôlé montre l'effet :

printf 'nom = valeur\n' > "$lab/espaces-a.txt"
printf 'nom  = valeur\n' > "$lab/espaces-b.txt"
diff -q -- "$lab/espaces-a.txt" "$lab/espaces-b.txt"
diff -q -b -- "$lab/espaces-a.txt" "$lab/espaces-b.txt"

Le premier appel signale une différence ; le second ne doit rien afficher et renvoie 0, car la variation de quantité de blancs est ignorée. Retirez -b pour retrouver une comparaison sensible aux espaces. Ne concluez pas que les fichiers sont identiques octet par octet à partir du second résultat.

Conserver un correctif et vérifier son sens

Une sortie unifiée peut être enregistrée pour revue ou pour un outil de correction. Ici, les en-têtes contiennent des chemins vers le dossier temporaire ; contrôlez toujours les chemins cibles avant d'appliquer un correctif à un autre environnement.

diff -u -- "$lab/ancien.conf" "$lab/nouveau.conf" > "$lab/changement.patch"
status=$?
if test "$status" -eq 1; then
  printf 'Correctif créé : %s\n' "$lab/changement.patch"
elif test "$status" -eq 0; then
  printf 'Aucune modification à enregistrer\n'
else
  printf 'Échec de la comparaison : %s\n' "$status" >&2
fi

Ouvrez changement.patch avec un lecteur de texte et vérifiez les en-têtes --- et +++, puis chaque bloc @@. Ce fichier n'a d'intérêt que si la comparaison s'est terminée normalement avec le code 1. Pour produire un correctif destiné à une autre arborescence, choisissez une racine de travail et des chemins relatifs cohérents, et vérifiez son application sur une copie avant toute modification du projet réel.

Quand utiliser diff plutôt que cmp ou Git ?

diff répond à la question « quelles lignes de texte ont changé ? ». Pour savoir si deux fichiers sont identiques octet par octet ou localiser leur premier octet différent, utilisez la commande cmp. git diff ajoute la connaissance d'un dépôt, de son index et de ses commits ; il convient aux modifications suivies par Git. comm répartit les lignes communes et propres à deux entrées préalablement triées : ce n'est pas le même problème qu'un correctif ligne par ligne.

Les fichiers binaires ne se lisent généralement pas comme des lignes. GNU diff peut seulement signaler qu'ils diffèrent ; ne forcez une sortie texte avec -a que si vous savez interpréter les données. Un résultat d'égalité de diff ne compare pas non plus les métadonnées du fichier.

Questions fréquentes

Pourquoi diff ne produit-il aucune sortie ?

S'il renvoie 0, il n'a trouvé aucune différence selon les options utilisées. Vérifiez le code de sortie et la portée de la comparaison avant de conclure à l'égalité des fichiers.

Le code 1 signifie-t-il que la commande a échoué ?

Non. Dans GNU diff, 1 signifie que des différences ont été trouvées ; 2 désigne un problème de comparaison.

Comment obtenir seulement la liste des fichiers différents dans deux dossiers ?

Utilisez diff -qr DOSSIER_A DOSSIER_B. -r parcourt les sous-dossiers et -q réduit le détail affiché.

La référence des commandes Linux par tâche situe diff parmi les autres outils de comparaison et de recherche.