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
.
unix
shell
command-line
zu viel php
quelle
quelle
comm
sortierte Eingabedateien erforderlich sind. Wenn Sie nur Zeile für Zeile gemeinsam möchten, ist es großartig. Aber wenn Sie wollen, was ich "Anti-Diff" nennen würde,comm
machen Sie den Job nicht.pr-123-xy-45
und Datei2 enthältec11_orop_pr-123-xy-45.gz
. Ich brauche Datei3 mitec11_orop_pr-123-xy-45.gz
Antworten:
Der Befehl, den Sie suchen, ist
comm
. z.B:-Hier:
-1 : Spalte 1 unterdrücken (Zeilen eindeutig für 1.sorted.txt)
-2 : Spalte 2 unterdrücken (Zeilen eindeutig für 2.sorted.txt)
quelle
grep
macht einige seltsame Dinge, die Sie möglicherweise nicht erwarten. Insbesondere wird alles in1.txt
als regulärer Ausdruck und nicht als einfache Zeichenfolge interpretiert. Außerdem stimmt jede leere Zeile in1.txt
mit allen Zeilen in überein2.txt
. Funktioniert alsogrep
nur in ganz bestimmten Situationen. Sie möchten zumindestfgrep
(odergrep -f
) verwenden, aber die leere Zeile wird wahrscheinlich Chaos in diesem Prozess anrichten.grep -F -x -f file1 file2
.comm
Befehls in 3 separate Dateien bringt. Die Antwort war viel zu groß, um hier bequem zu passen.Verwenden Sie die Prozessersetzung von Bash, um den Befehl comm einfach auf unsortierte Dateien anzuwenden :
Die Dateien abc und def haben also eine Zeile gemeinsam, die mit "132". Verwenden von comm für unsortierte Dateien:
Die letzte Zeile erzeugte keine Ausgabe, die gemeinsame Zeile wurde nicht entdeckt.
Verwenden Sie jetzt comm für sortierte Dateien und sortieren Sie die Dateien mit Prozessersetzung:
Jetzt haben wir die Linie 132!
quelle
sort abc > abc.sorted
,sort dev > def.sorted
und danncomm -12 abc.sorted def.sorted
?Als Ergänzung zum Perl-Einzeiler ist hier das
awk
Äquivalent:Dadurch werden alle Zeilen
file1
in das Array eingelesenarr[]
und anschließend für jede Zeile überprüft,file2
ob sie bereits im Array vorhanden ist (dhfile1
). Die gefundenen Zeilen werden in der Reihenfolge gedruckt, in der sie angezeigt werdenfile2
. Beachten Sie, dass der Vergleichin arr
die gesamte Zeile vonfile2
als Index für das Array verwendet, sodass nur genaue Übereinstimmungen für ganze Zeilen gemeldet werden.quelle
perl
, weil). Vielen Dank, FrauVielleicht meinst du
comm
?Das Geheimnis beim Auffinden dieser Informationen sind die Infoseiten. Für GNU-Programme sind sie viel detaillierter als ihre Manpages. Versuchen Sie es
info coreutils
und es werden Ihnen alle kleinen nützlichen Hilfsprogramme aufgelistet.quelle
Während
gibt Ihnen die Unterschiede von zwei Dateien (was in 2.txt und nicht in 1.txt ist), könnten Sie leicht eine tun
alle gemeinsamen Zeilen zu sammeln, die eine einfache Lösung für Ihr Problem bieten sollten. Wenn Sie Dateien sortiert haben, sollten Sie
comm
trotzdem nehmen . Grüße!quelle
grep
macht einige seltsame Dinge, die Sie vielleicht nicht erwarten. Insbesondere wird alles in1.txt
als regulärer Ausdruck und nicht als einfache Zeichenfolge interpretiert. Außerdem stimmt jede leere Zeile in1.txt
mit allen Zeilen in überein2.txt
. Dies funktioniert also nur in ganz bestimmten Situationen.grep
Notationen besser zu funktionieren , die von dengrep
meisten modernen Unix-Varianten unterstützt werden. Hinzufügen-F
(oder Verwendenfgrep
), um reguläre Ausdrücke zu unterdrücken. Fügen Sie-x
(genau) hinzu, um nur ganze Zeilen abzugleichen.comm
für sortierte Dateien nehmen?comm
kann mit beliebig großen Dateien arbeiten, solange sie sortiert sind, da immer nur drei Zeilen im Speicher gespeichert werden müssen (ich vermute, GNUcomm
würde sogar wissen, dass nur ein Präfix beibehalten werden muss, wenn die Zeilen wirklich lang sind). Diegrep
Lösung muss alle Suchausdrücke im Speicher behalten.quelle
comm
Befehl , wie es jede Zeile suchtfile1
infile2
denencomm
nur vergleichen , wenn Zeilen
infile1
mit der Leitung gleichn
infile2
.comm
vergleicht nicht einfach Zeile N in Datei1 mit Zeile N in Datei2. Es kann eine Reihe von Zeilen, die in eine der beiden Dateien eingefügt wurden, perfekt verwalten (was natürlich dem Löschen einer Reihe von Zeilen aus der anderen Datei entspricht). Es ist lediglich erforderlich, dass die Eingaben in sortierter Reihenfolge vorliegen.comm
Antworten, wenn man die Reihenfolge halten will. Besser als zuawk
antworten, wenn man keine Duplikate will.Wenn die beiden Dateien noch nicht sortiert sind, können Sie Folgendes verwenden:
und es wird funktionieren, um die Fehlermeldung zu vermeiden ,
comm: file 2 is not in sorted order
wenn dabeicomm -12 a.txt b.txt
.quelle
<(command)
nicht auf die POSIX-Shell portierbar ist, obwohl sie in Bash und einigen anderen funktioniert.quelle
Auf einer eingeschränkten Linux-Version (wie einem QNAP (nas), an dem ich gearbeitet habe):
grep -f file1 file2
kann einige Probleme verursachen, wie von @ChristopherSchultz gesagt, und die Verwendunggrep -F -f file1 file2
war sehr langsam (mehr als 5 Minuten - nicht beendet - über 2-3 Sekunden mit der folgenden Methode bei Dateien über 20 MB)Also hier ist was ich getan habe:
Wenn
files.same.sorted
es in derselben Reihenfolge wie die ursprünglichen gewesen sein soll, fügen Sie diese Zeile in derselben Reihenfolge wie Datei1 hinzu:oder für dieselbe Reihenfolge wie Datei2:
quelle
Nur als Referenz, wenn noch jemand nach Möglichkeiten sucht, dies für mehrere Dateien zu tun, lesen Sie die verknüpfte Antwort auf Suchen nach übereinstimmenden 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:
Speichern Sie es einfach, geben Sie ihm Ausführungsrechte (
chmod +x compareFiles.sh
) und führen Sie es aus. Es werden alle im aktuellen Arbeitsverzeichnis vorhandenen Dateien verwendet und ein All-vs-All-Vergleich durchgeführt, wobei das Ergebnis in der Datei "Matching_lines" verbleibt.Dinge, die verbessert werden müssen:
quelle
Das sollte es tun.
quelle
rm -f file3.txt
wenn Sie die Datei löschen möchten. Das meldet keinen Fehler, wenn die Datei nicht existiert. OTOH, es wäre nicht notwendig, wenn Ihr Skript einfach auf die Standardausgabe zurückgreift und der Benutzer des Skripts auswählen kann, wohin die Ausgabe gehen soll. Letztendlich möchten Sie wahrscheinlich$1
und$2
(Befehlszeilenargumente) anstelle fester Dateinamen (file1.out
undfile2.out
) verwenden. Damit bleibt der Algorithmus: Es wird langsam. Es wirdfile2.out
einmal für jede Zeile in gelesenfile1.out
. Es wird langsam sein, wenn die Dateien groß sind (sagen wir mehrere Kilobyte).grep -F
dieses liest eine Datei in den Speicher und führt dann einen einzigen Durchlauf über die andere aus, um zu vermeiden, dass beide Eingabedateien wiederholt durchlaufen werden.