web-dev-qa-db-fra.com

Rechercher les lignes d'un fichier qui ne sont pas présentes dans un autre fichier

J'ai deux fichiers (disons a.txt et b.txt), qui ont tous deux une liste de noms. J'ai déjà exécuté sort sur les deux fichiers.

Maintenant, je veux trouver des lignes de a.txt qui ne sont pas présents dans b.txt.

(J'ai passé beaucoup de temps à trouver la réponse à cette question, donc à documenter pour référence future)

85
Sudar

La commande que vous devez utiliser n’est pas diff mais comm

comm -23 a.txt b.txt

Par défaut, comm génère 3 colonnes: gauche seulement, droite seulement, les deux. Le -1, -2 et -3 _ supprime ces colonnes.

Alors, -23 masque les colonnes à droite et les deux, montrant les lignes qui apparaissent uniquement dans le premier fichier (à gauche).

Si vous voulez trouver des lignes qui apparaissent dans les deux cas, vous pouvez utiliser -12, qui masque les colonnes gauche seulement et droite seulement, ne vous laissant que la colonne les deux.

144
Sudar

La réponse simple n'a pas fonctionné pour moi car je n'avais pas réalisé que comm correspondait ligne par ligne. Les lignes dupliquées dans un fichier seront donc imprimées comme n'étant pas existantes dans l'autre. Par exemple, si fichier1 contenait:

Alex
Bill
Fred

Et file2 contenait:

Alex
Bill
Bill
Bill
Fred

Alors comm -13 file1 file2 Produirait:

Bill
Bill

Dans mon cas, je voulais seulement savoir que chaque chaîne de file2 existait dans file1, quel que soit le nombre de fois que cette ligne se soit produite dans chaque fichier.

Solution 1: utilisez l'indicateur -u (Unique) pour sort:

comm -13 <(sort -u file1) <(sort -u file2)

Solution 2: (la première réponse "de travail" que j'ai trouvée) de nix.stackexchange :

fgrep -v -f file1 file2

Notez que si fichier2 contient des lignes en double qui n'existent pas du tout dans fichier1, fgrep produira chacune des lignes en double. Notez également que mes tests totalement non scientifiques sur un seul ordinateur portable pour un seul ensemble de données (assez volumineux) ont montré que la solution 1 (avec comm) était presque 5 fois plus rapide que la solution 2 (avec fgrep ).

28
Johann

Je ne suis pas sûr de savoir pourquoi il a été dit que diff ne devrait pas être utilisé. Je l’utiliserais pour comparer les deux fichiers, puis pour afficher uniquement les lignes qui se trouvent dans le fichier de gauche mais pas dans le fichier de droite. Ces lignes sont signalées par diff avec < donc il suffit de grep ce symbole au début de la ligne

diff a.txt b.txt  | grep \^\<
7
simonemainardi

Si les fichiers ne sont pas encore triés, vous pouvez utiliser:

comm -23 <(sort a.txt) <(sort b.txt)
5
Basj