Linux / Commande comm : comparer les lignes communes et distinctes

comm compare deux fichiers triés ligne par ligne et répartit le résultat en trois colonnes : les lignes propres au premier, celles propres au second et celles communes aux deux. Pour ne garder qu'une catégorie, masquez les autres colonnes avec -1, -2 ou -3. Les deux entrées doivent être triées selon les mêmes règles que la comparaison.

Cet outil est utile pour comparer des listes de valeurs. Si vous voulez examiner les changements dans l'ordre original d'un document, un comparatif de fichiers avec diff répond à une autre question : le tri préalable de comm ferait disparaître l'information de position.

Préparer et trier les deux listes

comm [options] fichier1 fichier2

Pour suivre les exemples avec GNU comm dans Bash, préparez des fichiers fictifs dans un nouveau répertoire :

comm_lab=$(mktemp -d "$HOME/comm-lab.XXXXXX")
cd -- "$comm_lab"
printf 'banana\napple\n' > old.txt
printf 'cherry\nbanana\n' > new.txt
LC_ALL=C sort old.txt > old.sorted
LC_ALL=C sort new.txt > new.sorted

Les copies triées conservent les originaux. LC_ALL=C fixe une comparaison selon la locale C ; utilisez aussi cette valeur pour comm. Un tri numérique ou un tri sur une partie de ligne n'est pas en général équivalent au tri de la ligne entière requis ici. Pour les autres usages du tri, consultez les critères de comparaison de sort.

Notez le chemin du répertoire d'exercice si vous voulez retrouver les fichiers ; vous pourrez le quitter avec cd "$HOME". Consultez man comm pour le manuel de votre système. L'option --check-order employée ci-dessous appartient à GNU comm.

Lire les trois colonnes par défaut

LC_ALL=C comm --check-order old.sorted new.sorted

La sortie contient une ligne pour chaque catégorie rencontrée, avec des tabulations initiales pour matérialiser les colonnes :

apple
		banana
	cherry
Colonne Sens Exemple
1 Ligne présente uniquement dans le premier fichier. apple
2 Ligne présente uniquement dans le second fichier. cherry
3 Ligne commune aux deux fichiers. banana

Sans colonnes masquées, une ligne de la première catégorie n'a pas de tabulation de préfixe, la deuxième en a une et la troisième en a deux. L'alignement visuel dépend du terminal ; ne confondez pas ces tabulations de présentation avec le contenu réel des valeurs.

Afficher seulement la catégorie souhaitée

Les chiffres des options indiquent les colonnes à supprimer. Pour conserver la troisième, masquez donc les deux premières :

LC_ALL=C comm --check-order -12 old.sorted new.sorted
banana

Pour garder les lignes du second fichier absentes du premier, masquez les colonnes 1 et 3 :

LC_ALL=C comm --check-order -13 old.sorted new.sorted

Le résultat est cherry. Dans l'autre sens, -23 conserve seulement la colonne 1 :

LC_ALL=C comm --check-order -23 old.sorted new.sorted

Le résultat est apple. Quand une seule catégorie reste active, les tabulations de séparation des colonnes supprimées disparaissent. L'ordre des fichiers compte donc : l'inverser échange le sens des lignes propres à chaque entrée.

Décider comment traiter les doublons

Comm compare des lignes triées avec leurs occurrences ; il ne transforme pas automatiquement les fichiers en ensembles de valeurs distinctes. Préparez deux entrées déjà triées dont le nombre d'apple diffère :

printf 'apple\napple\nbanana\n' > repeated-first.txt
printf 'apple\nbanana\n' > repeated-second.txt
LC_ALL=C comm --check-order -23 repeated-first.txt repeated-second.txt
LC_ALL=C comm --check-order -12 repeated-first.txt repeated-second.txt

La première commande affiche un apple supplémentaire du premier fichier. La seconde affiche apple et banana, qui ont chacune une occurrence appariée. Une valeur peut ainsi apparaître dans une catégorie commune et dans une catégorie propre à un fichier lorsque ses répétitions ne sont pas les mêmes.

Si votre question porte uniquement sur la présence d'une valeur, dédupliquez les lignes entières avant comparaison :

LC_ALL=C sort -u repeated-first.txt > first-set.sorted
LC_ALL=C sort -u repeated-second.txt > second-set.sorted
LC_ALL=C comm --check-order -23 first-set.sorted second-set.sorted

Cette fois, aucune ligne n'est affichée : les valeurs distinctes sont les mêmes. La suppression des répétitions change la question posée aux données. Si les quantités sont importantes, conservez-les et choisissez une méthode qui les rend explicites, par exemple le comptage de groupes avec uniq avant une analyse adaptée.

Vérifier le tri et interpréter le statut de sortie

--check-order provoque une erreur si l'une des entrées est désordonnée. Si cette vérification échoue, corrigez le tri et relancez la comparaison ; une éventuelle sortie partielle n'est pas un résultat utilisable. L'absence de message sans vérification explicite ne prouve pas que les conditions d'entrée sont respectées.

Un statut 0 de comm signifie que la commande s'est terminée normalement, pas que les fichiers sont identiques. Avec nos listes différentes :

LC_ALL=C comm --check-order -12 old.sorted new.sorted
printf 'Statut : %s\n' "$?"
banana
Statut : 0

Ne déduisez donc pas la présence de différences du seul code de sortie comme vous pourriez le faire avec un autre outil de comparaison. Dans un script, vérifiez d'abord que comm réussit, puis examinez la catégorie de résultat correspondant à votre besoin.

Conserver une liste et choisir les options

Pour enregistrer les valeurs du second fichier absentes du premier, choisissez un nouveau nom de sortie :

LC_ALL=C comm --check-order -13 old.sorted new.sorted > added.txt
cat added.txt

Le fichier contient cherry. Une fois les listes traitées comme valeurs distinctes et les rôles ancien/nouveau définis, ce résultat peut servir de liste d'ajouts. Ne redirigez pas vers un fichier d'entrée ni vers un document à conserver : le shell peut écraser la destination avant la lecture.

Option Effet
-1 Masquer les lignes propres au fichier 1.
-2 Masquer les lignes propres au fichier 2.
-3 Masquer les lignes communes.
-12 Ne conserver que les lignes communes.
-13 Ne conserver que les lignes propres au fichier 2.
-23 Ne conserver que les lignes propres au fichier 1.
--check-order Avec GNU comm, refuser explicitement une entrée mal triée.

Les règles de locale, de séparation des colonnes et de statut de sortie sont précisées dans le manuel officiel de GNU comm.