it-swarm.com.de

Unix-Befehl zum Auffinden von Zeilen, die in zwei Dateien gemeinsam sind

Ich bin sicher, ich habe einmal einen Unix-Befehl gefunden, der die gemeinsamen Zeilen aus zwei oder mehr Dateien drucken kann. Kennt jemand seinen Namen? Es war viel einfacher als diff.

167
too much php

Der gesuchte Befehl lautet comm . z.B:-

comm -12 1.sorted.txt 2.sorted.txt

Hier:

- 1 : Unterdrückt Spalte 1 (Zeilen, die nur in 1.sorted.txt vorkommen)

- 2 : Unterdrückt Spalte 2 (Zeilen, die für 2.sorted.txt eindeutig sind)

200

Um den Befehl comm einfach auf unsortierte Dateien anzuwenden, verwenden Sie Bashs - Prozessersetzung :

$ bash --version
GNU bash, version 3.2.51(1)-release
Copyright (C) 2007 Free Software Foundation, Inc.
$ cat > abc
123
567
132
$ cat > def
132
777
321

Die Dateien abc und def haben also eine Zeile gemeinsam, die mit "132". Verwenden von comm für unsortierte Dateien:

$ comm abc def
123
    132
567
132
    777
    321
$ comm -12 abc def # No output! The common line is not found
$

Die letzte Zeile brachte keine Ausgabe, die gemeinsame Zeile wurde nicht entdeckt.

Verwenden Sie jetzt comm für sortierte Dateien und sortieren Sie die Dateien mit Prozessersetzung:

$ comm <( sort abc ) <( sort def )
123
            132
    321
567
    777
$ comm -12 <( sort abc ) <( sort def )
132

Jetzt haben wir die 132er Linie!

58
Stephan Wehner

Um den Perl-Einzeiler zu ergänzen, gibt es hier das Äquivalent awk:

awk 'NR==FNR{arr[$0];next} $0 in arr' file1 file2

Dies liest alle Zeilen von file1 In das Array arr[] Und prüft dann für jede Zeile in file2, Ob sie bereits im Array vorhanden ist (dh file1 ). Die gefundenen Zeilen werden in der Reihenfolge gedruckt, in der sie in file2 Erscheinen. Beachten Sie, dass der Vergleich in arr Die gesamte Zeile von file2 Als Index für das Array verwendet, sodass nur exakte Übereinstimmungen für ganze Zeilen gemeldet werden.

25
Tatjana Heuser

Vielleicht meinst du comm?

Vergleichen Sie die sortierten Dateien FILE1 und FILE2 zeilenweise.

Ohne Optionen können Sie dreispaltige Ausgaben erstellen. Spalte eins enthält Zeilen, die für DATEI1 eindeutig sind, Spalte zwei enthält Zeilen, die für DATEI2 eindeutig sind, und Spalte drei enthält Zeilen, die für beide Dateien gleich sind.

Das Geheimnis beim Auffinden dieser Informationen sind die Infoseiten. Für GNU Programme sind sie viel detaillierter als ihre Man-Pages. Versuchen Sie info coreutils und es werden alle kleinen nützlichen Utensilien aufgelistet.

Während

grep -v -f 1.txt 2.txt > 3.txt

gibt man die Unterschiede zweier Dateien an (was in 2.txt und nicht in 1.txt steht), könnte man problemlos eine

grep -f 1.txt 2.txt > 3.txt

alle gängigen Leitungen zu sammeln, die eine einfache Lösung für Ihr Problem bieten sollen. Wenn Sie Dateien sortiert haben, sollten Sie trotzdem comm nehmen. Grüße!

18
ferdy

Wenn die beiden Dateien noch nicht sortiert sind, können Sie Folgendes verwenden:

comm -12 <(sort a.txt) <(sort b.txt)

und es wird funktionieren, unter Vermeidung der Fehlermeldung comm: file 2 is not in sorted order wenn comm -12 a.txt b.txt.

8
Basj
Perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2
8
user2592005
awk 'NR==FNR{a[$1]++;next} a[$1] ' file1 file2
5
R S John

Auf einer eingeschränkten Version von Linux (wie einem QNAP (nas), an dem ich gearbeitet habe):

  • comm existierte nicht
  • grep -f file1 file2 kann einige Probleme verursachen, wie von @ChristopherSchultz und der Verwendung von grep -F -f file1 file2 war sehr langsam (mehr als 5 Minuten - nicht beendet - über 2-3 Sekunden mit der unten beschriebenen Methode für Dateien über 20 MB)

Also hier ist was ich getan habe:

sort file1 > file1.sorted
sort file2 > file2.sorted

diff file1.sorted file2.sorted | grep "<" | sed 's/^< *//' > files.diff
diff file1.sorted files.diff | grep "<" | sed 's/^< *//' > files.same.sorted

Ob files.same.sorted muss in der gleichen Reihenfolge wie das Original sein, dann füge diese Zeile in der gleichen Reihenfolge wie file1 hinzu:

awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file1 > files.same

oder für die gleiche Reihenfolge wie file2:

awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file2 > files.same
3
Master DJon

Nur als Referenz, wenn jemand noch nach einer Vorgehensweise für mehrere Dateien sucht, lesen Sie die verknüpfte Antwort auf Finden übereinstimmender Zeilen in vielen Dateien.


Wenn Sie diese beiden Antworten ( ans1 und ans2 ) kombinieren, können Sie das gewünschte Ergebnis erzielen, ohne die Dateien zu sortieren:

#!/bin/bash
ans="matching_lines"

for file1 in *
do 
    for file2 in *
        do 
            if  [ "$file1" != "$ans" ] && [ "$file2" != "$ans" ] && [ "$file1" != "$file2" ] ; then
                echo "Comparing: $file1 $file2 ..." >> $ans
                Perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' $file1 $file2 >> $ans
            fi
         done 
done

Einfach speichern, ausführen lassen (chmod +x compareFiles.sh) und starte es. Es werden alle im aktuellen Arbeitsverzeichnis vorhandenen Dateien verwendet und ein All-gegen-All-Vergleich durchgeführt, wobei das Ergebnis in der Datei "matching_lines" verbleibt.

Dinge, die verbessert werden müssen:

  • Verzeichnisse überspringen
  • Vermeiden Sie es, alle Dateien zweimal zu vergleichen (Datei1 vs. Datei2 und Datei2 vs. Datei1).
  • Fügen Sie möglicherweise die Zeilennummer neben der entsprechenden Zeichenfolge hinzu
2
akarpovsky