Drucken von Zeilen aus einer Datei, wenn ein Teil davon in einer anderen angezeigt wird. Beide Dateien sind Millionen Zeilen lang

7

Ich habe zwei Dateien, nennen wir sie 123.txtund 789.txt. 123.txtist 2,5 Millionen Zeilen lang und 65 Millionen 789.txtZeilen lang. Gibt es eine Möglichkeit, grepZeilen 789.txt, die Zeilen enthalten , zu verwenden oder ähnliches zu verwenden?123.txt?

Es wird maximal ein Duplikat pro Zeile geben 789.txt, und der doppelte Text befindet sich am Anfang der Zeile. Ich bin total festgefahren und konnte online keine Informationen finden, also habe ich eigentlich nichts zu Beginn. Es wird auf einem Server ausgeführt, daher macht es mir nichts aus, dass es eine Weile dauert (was ich weiß).

  • 123.txt:

    hxxp://www.a.com
    hxxp://www.b.com
    hxxp://www.c.com
    
  • 789.txt:

    hxxp://www.a.com/kgjdk-jgjg/
    hxxp://www.b.com/gsjahk123/
    hxxp://www.c.com/abc.txt
    hxxp://www.d.com/sahgsj/
    
  • Gewünschte Ausgabe:

    hxxp://www.a.com/kgjdk-jgjg/
    hxxp://www.b.com/gsjahk123/
    hxxp://www.c.com/abc.txt
    
Joe
quelle

Antworten:

13

Sie können dies sehr einfach tun, indem Sie grep:

$ grep -Ff 123.txt 789.txt
http://www.a.com/kgjdk-jgjg/ 
http://www.b.com/gsjahk123/ 
http://www.c.com/abc.txt 

Der obige Befehl druckt alle Zeilen aus einer Datei 789.txt, die eine der Zeilen aus enthält 123.txt. Das -f bedeutet "Lesen Sie die zu durchsuchenden Muster aus dieser Datei" und das -F weist grep an, die Suchmuster als Zeichenfolgen und nicht als reguläre Standardausdrücke zu behandeln.

Dies funktioniert nicht, wenn die Zeilen von 123.txtnachgestellten Leerzeichen enthalten. Behandelt grepdie Leerzeichen als Teil des zu suchenden Musters und stimmt nicht überein, wenn sie innerhalb eines Wortes auftreten. Beispielsweise stimmt das Muster foo (beachten Sie den nachgestellten Leerzeichen) nicht überein foobar. Führen Sie den folgenden Befehl aus, um nachgestellte Leerzeichen aus Ihrer Datei zu entfernen:

$ sed 's/ *$//' 123.txt > new_file

Verwenden Sie dann das new_filezu grep:

$ grep -Ff new_file 789.txt

Sie können dies auch ohne eine neue Datei tun, indem Sie das iFlag verwenden:

$ sed -i.bak 's/ *$//' 123.txt

Dadurch wird die Datei geändert 123.txtund eine Kopie des aufgerufenen Originals aufbewahrt 123.txt.bak.

(Beachten Sie, dass diese Form des -iFlags seddavon ausgeht, dass Sie GNU haben sed; für die BSD- sedVerwendung -i .bakmit einem Leerzeichen dazwischen.)

terdon
quelle
Ich denke nicht, dass die erste Option funktionieren würde, unabhängig vom Fall des OP: Es würde Zeilen drucken 123.txt, die nicht in sind 789.txt, sowie Zeilen 789.txt, die in erscheinen 123.txt(sie werden nur einmal gedruckt, aber trotzdem gedruckt).
Joseph R.
3
@ JosephR. Du hast absolut recht, mein Schlechtes. Ich habe diesen Vorschlag entfernt. Vielen Dank für den Hinweis.
Terdon
Hallo, vielen Dank :) Es funktioniert fast, aber es gibt zwei kleine Dinge - es sollte diejenigen behalten, die mit der anderen Datei übereinstimmen, und die teilweise Übereinstimmung für das Perl scheint in einem Test I nicht ganz zu funktionieren lief, es scheint zu sein, weil alle meine Zeilen keine Leerzeichen enthalten. Es tut mir leid für die Noobishness, meine Perl-Fähigkeiten sind nicht sehr gut.
Joe
@ Joe kein Problem. Könnten Sie Ihrer Frage einige Beispieleingaben hinzufügen, damit ich eine bessere Vorstellung davon bekomme, was Sie brauchen? Geben Sie auch die gewünschte Ausgabe an.
Terdon
Hallo, vielen Dank, das funktioniert fast für mich, aber ich bekomme anscheinend nur vollständige und keine teilweisen Übereinstimmungen.
Joe
4

Wenn die Dateien wie in Ihrem Beispiel sortiert sind und immer diesem Muster folgen, können Sie es schreiben:

join -t/ -1 3 -2 3 123.txt 789.txt |
  sed -n 's,\([^/]*/\)\([^/]*://\)\2,\2\1,p'

Das wäre am effizientesten.

Stéphane Chazelas
quelle