comment afficher les lignes en commun (diff inversé)?

170

J'ai une série de fichiers texte pour lesquels j'aimerais connaître les lignes en commun plutôt que les lignes qui sont différentes entre elles. La ligne de commande unix ou windows est très bien.

toto:

linux-vdso.so.1 =>  (0x00007fffccffe000)
libvlc.so.2 => /usr/lib/libvlc.so.2 (0x00007f0dc4b0b000)
libvlccore.so.0 => /usr/lib/libvlccore.so.0 (0x00007f0dc483f000)
libc.so.6 => /lib/libc.so.6 (0x00007f0dc44cd000)

bar:

libkdeui.so.5 => /usr/lib/libkdeui.so.5 (0x00007f716ae22000)
libkio.so.5 => /usr/lib/libkio.so.5 (0x00007f716a96d000)
linux-vdso.so.1 =>  (0x00007fffccffe000)

Donc, étant donné ces deux fichiers ci-dessus, la sortie de l'utilitaire souhaité serait similaire à file1:line_number, file2:line_number == matching text (juste une suggestion, je ne me soucie vraiment pas de la syntaxe):

foo:1, bar:3 == linux-vdso.so.1 =>  (0x00007fffccffe000)

Merci.

matt wilkie
la source
@ChristopherSchultz Mon erreur. La 1ère ligne du 1er exemple correspond à la dernière ligne du 2ème exemple. Merci d'avoir attrapé l'erreur; en changeant.
matt wilkie
1
Une autre question similaire avec de bonnes réponses: unix.stackexchange.com/questions/1079/…
MortezaE

Réponses:

210

Sur * nix, vous pouvez utiliser comm . La réponse à la question est:

comm -1 -2 file1.sorted file2.sorted 
# where file1 and file2 are sorted and piped into *.sorted

Voici l'utilisation complète de comm:

comm [-1] [-2] [-3 ] file1 file2
-1 Suppress the output column of lines unique to file1.
-2 Suppress the output column of lines unique to file2.
-3 Suppress the output column of lines duplicated in file1 and file2. 

Notez également qu'il est important de trier les fichiers avant d'utiliser comm, comme mentionné dans les pages de manuel.

Dan Lew
la source
3
comm [-1] [-2] [-3] fichier1 fichier2 -1 Supprime la colonne de sortie de lignes uniques à fichier1. -2 Supprime la colonne de sortie des lignes uniques à file2. -3 Supprime la colonne de sortie des lignes dupliquées dans fichier1 et fichier2.
ojblass le
@ojblass: Ajouté ceci à la réponse.
Matt J
6
J'ai découvert qu'il était important que les fichiers soient triés avant d'utiliser comm. Ajoutez peut-être cela à la réponse.
matt wilkie le
11
réponse courte à la question: comm -1 -2 fichier1 fichier2
greggles
6
Vous pouvez l'utiliser si vos fichiers ne sont pas triés: comm -1 -2 <(tri filename1) <(tri filename2)
Kevin Wheeler
56

J'ai trouvé cette réponse sur une question répertoriée comme un doublon . Je trouve que grep est plus convivial que comm, donc si vous voulez juste l'ensemble des lignes correspondantes (utile pour comparer les CSV, par exemple) utilisez simplement

grep -F -x -f file1 file2

ou la version simplifiée de fgrep

fgrep -xf file1 file2

De plus, vous pouvez utiliser file2*pour effectuer une recherche globale et rechercher des lignes en commun avec plusieurs fichiers, plutôt que deux.

Certaines autres variantes pratiques incluent

  • -n drapeau pour afficher le numéro de ligne de chaque ligne correspondante
  • -c pour ne compter que le nombre de lignes qui correspondent
  • -vpour afficher uniquement les lignes du fichier2 qui diffèrent (ou utiliserdiff ).

L'utilisation commest plus rapide, mais cette vitesse se fait au détriment de la nécessité de trier d'abord vos fichiers. Ce n'est pas très utile comme «diff inversé».

Ryder
la source
merci Ryder, cela pourrait être plus utile que la communication pour beaucoup. Vous devriez créer un lien vers la réponse source (il y en a plus d'une demi-douzaine de liens dans Q dans la navigation de droite; c'est un peu de travail à trouver). Il serait également intéressant de savoir à quel point grep fonctionne bien avec une entrée triée non ou différemment, et peut imprimer les numéros de ligne respectifs des correspondances.
matt wilkie
1
@mattwilkie J'ai ressenti le besoin de revenir et de clarifier l'utilisation du -v drapeau après l'avoir glissé moi-même. Supposons que vous ayez deux fichiers csv file1 et file2 et qu'ils aient à la fois des lignes qui se chevauchent et qui ne se chevauchent pas. Si vous voulez toutes et uniquement les lignes fgrep -v file1 file2qui ne se chevauchent pas, l'utilisation ne renverra que les lignes qui ne se chevauchent pas dans fichier2, et aucune des lignes non chevauchantes supplémentaires dans fichier1 . Cela peut être évident pour certains, mais il vaut mieux énoncer l'évidence que le risque d'une mauvaise interprétation. Dans ce cas particulier, trier les fichiers et utiliser commreste le meilleur choix.
Ryder
1
Merci d'être revenu et d'avoir clarifié Ryder. L'attention supplémentaire est notée et appréciée (tout est facile à laisser filer les vieilles choses!). J'ai changé la réponse acceptée parce que la communication est clairement le choix de la communauté, même si personnellement je l'utilise toujours lorsque le tri est une surcharge indésirable.
matt wilkie
2
Autre complication lors de l'utilisation grep: toute ligne vide du premier fichier correspondra à toutes les lignes du second fichier. Assurez-vous qu'il file1n'y a pas de lignes vides, sinon il semblera que les fichiers sont identiques.
Christopher Schultz
grep -FxfC'est pour moi.
loxaxs
35

A été demandé ici avant: Commande Unix pour trouver des lignes communes dans deux fichiers

Vous pouvez également essayer avec perl (crédit va ici )

perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2
ChristopheD
la source
1
Merci. J'aurais aimé accepter les deux réponses, car le perl one liner est multi-plateforme. Comm obtient le signe de tête parce que c'est plus simple.
matt wilkie le
1
Parfait. Utilisation du terminal cygwin sur Windows et commn'était pas facilement disponible. C'était l'alternative parfaite.
Qix - MONICA A ÉTÉ BRUYÉ
3
Cela ne se soucie pas de la façon dont les lignes sont ordonnées. C'est plus précis que comm.
enl8enmentnow
1
Une explication est ici: stackoverflow.com/questions/17552789/…
Chris Koknat
17

Je viens d'apprendre la commande comm de ce thread, mais je voulais ajouter quelque chose de plus: si les fichiers ne sont pas triés et que vous ne voulez pas toucher les fichiers d'origine, vous pouvez diriger la sortie de la commande de tri. Cela laisse les fichiers originaux intacts. Fonctionne en bash, je ne peux pas dire sur les autres coquilles.

comm -1 -2 <(sort file1) <(sort file2)

Cela peut être étendu pour comparer la sortie de commande, au lieu de fichiers:

comm -1 -2 <(ls /dir1 | sort) <(ls /dir2 | sort)
Greg Mueller
la source
9

Le moyen le plus simple est de:

awk 'NR==FNR{a[$1]++;next} a[$1] ' file1 file2

Les fichiers ne doivent pas être triés.

Gopu
la source
1
Ceci est différent de la plupart des réponses ici en ce sens que cela vous permet de reconstruire des modèles source. J'ai deux fichiers construits à partir du même wrapper, avec un texte différent inséré à quelques points. Cette réponse m'a permis de récupérer le wrapper.
Lucas Gonze
1

Juste pour information, j'ai créé un petit outil pour Windows faisant la même chose que "grep -F -x -f fichier1 fichier2" (car je n'ai rien trouvé d'équivalent à cette commande sous Windows)

La voici: http://www.nerdzcore.com/?page=commonlines

L'utilisation est "CommonLines inputFile1 inputFile2 outputFile"

Le code source est également disponible (GPL)

Zivilyn Bane
la source
1

Dans Windows, vous pouvez utiliser un script Powershell avec CompareObject

compare-object -IncludeEqual -ExcludeDifferent -PassThru (get-content A.txt) (get-content B.txt)> MATCHING.txt | Out-Null #Find Matching Lines

CompareObject:

  • IncludeEqual sans -ExcludeDifferent: Tout
  • ExcludeDifferent sans -InclueEqual: Nothing
Pie-grièche
la source