web-dev-qa-db-fra.com

Existe-t-il un outil pour obtenir les lignes d'un fichier qui ne se trouvent pas dans un autre?

Existe-t-il un outil pouvant obtenir des lignes que contient le fichier A, mais pas le fichier B? Je pourrais faire un petit script simple avec, par exemple, Perl, mais si quelque chose comme ça existe déjà, je vais économiser mon temps à partir de maintenant.

111
daisy

Oui. L'outil standard grep pour rechercher des fichiers de chaînes de texte peut être utilisé pour soustraire toutes les lignes d'un fichier d'un autre.

grep -F -x -v -f fileB fileA

Cela fonctionne en utilisant chaque ligne du fichier B comme modèle (-f fileB) et en le traitant comme une chaîne simple à mettre en correspondance (pas une expression régulière) (-F). Vous forcez le match à se produire sur toute la ligne (-x) et imprimer uniquement les lignes qui ne correspondent pas (-v). Par conséquent, vous imprimez les lignes du fichier A qui ne contiennent pas les mêmes données que n'importe quelle ligne du fichier B.

L'inconvénient de cette solution est qu'elle ne prend pas en compte l'ordre des lignes et si votre entrée contient des lignes en double à différents endroits, vous n'obtiendrez peut-être pas ce que vous attendez. La solution à cela est d'utiliser un véritable outil de comparaison tel que diff. Vous pouvez le faire en créant un fichier diff avec la valeur de contexte à 100% des lignes du fichier, puis en l'analysant uniquement pour les lignes qui seraient supprimées si vous convertissez le fichier A en fichier B. (Notez que cette commande supprime également la mise en forme diff après avoir obtenu les bonnes lignes.)

diff -U $(wc -l < fileA) fileA fileB | sed -n 's/^-//p' > fileC
162
Caleb

La réponse dépend beaucoup du type et du format des fichiers que vous comparez.

Si les fichiers que vous comparez sont des fichiers texte triés, alors l'outil GNU écrit par Richard Stallman et Davide McKenzie appelé comm peut effectuer le filtrage vous sont après. Il fait partie des coreutils.

Exemple

Supposons que vous ayez les 2 fichiers suivants:

$ cat a
1
2
3
4
5

$ cat b
1
2
3
4
5
6

Lignes dans le fichier b qui ne sont pas dans le fichier a:

$ comm <(sort a) <(sort b) -3
    6
59
A friend

de stackoverflow ...

comm -23 fichier1 fichier2

-23 supprime les lignes du fichier2 (-2) et les lignes qui apparaissent dans les deux (-3), ne laissant que les lignes uniques du fichier1. Les fichiers doivent être triés (ils sont dans votre exemple) mais sinon, dirigez-les d'abord par tri.

Voir la page man ici

-1 suppress column 1 (lines unique to FILE1)
-2 suppress column 2 (lines unique to FILE2)
-3 suppress column 3 (lines that appear in both files)
35
JJS

Les méthodes grep et comm (avec sort) prennent un temps long sur les gros fichiers. SiegeX et ghostdog74 ont partagé deux grands méthodes awk pour extraire des lignes uniques à l'un des deux fichiers sur Stack Overflow:

$ awk 'FNR==NR{a[$0]++}FNR!=NR && !a[$0]{print}' file1 file2

$ awk 'FNR==NR{a[$0]++;next}(!($0 in a))' file1 file2
9
Miles Wolbe

Si les fichiers sont volumineux et que vous n'avez pas de commande personnalisée pour vos entrées, grep prend beaucoup trop de temps. Une alternative rapide serait

sort file1 > 1 
sort file2 > 2 
diff 1 2 | grep "\>" | sed -e 's/> //'

[résultats file2-file1 à filtrer, pipe à classer etc.]

En changeant > à < obtiendrait la soustraction opposée. rm 1 2

5
Eshel Faraggi

Vous pouvez également envisager vimdiff, il met en évidence les différences entre les fichiers dans un éditeur vim

2
simona