"Ungrep" - welche Muster stimmen nicht überein

13

Ich suche einen Befehl oder ein Skript, um Folgendes auszuführen:

file1.txt:

abcd
efgh 
ijkl
mnop

file2.txt:

123abcd123
123efgh123
123mnop123

Ich möchte einen Befehl, der ungefähr so ​​aussieht:

ungrep file1.txt file2.txt

und gibt Folgendes zurück:

ijkl

Mit anderen Worten, es gibt mir die Zeilen in file1.txt, die bei einem grep von file2.txt keine Ergebnisse liefern. Ich weiß, dass ich dies tun kann, indem ich Datei1.txt durchlaufe, Datei2.txt für jede Zeile greife und das Ergebnis speichere und alle Zeilen ausgebe, in denen das Ergebnis leer ist, aber ich habe mir eine effizientere Möglichkeit erhofft, dies zu tun.

Edward Shtern
quelle

Antworten:

18

Mit GNU grepsollte folgendes funktionieren. Übergeben Sie die -fOption file1.txtals "Musterdatei", aber übergeben Sie sie auch ein zweites Mal als Datendatei. Verwenden Sie -odiese Option , um nur die passenden Teile zu melden. Extrahiert schließlich die Wörter, die nur einmal passen - diese entsprechen den Zeilen aus file1.txt, in denen keine Übereinstimmung gefunden wird file2.txt.

grep -h -o -f  file1.txt file2.txt file1.txt | sort | uniq -u
ijkl
iruvar
quelle
Sehr gute Beschreibung. Danke und +1.
Unxnut
4
Sie könnten den gleichen Effekt auch ohne die Grep-Schwierigkeit erzielen: sort file1.txt <(grep -of file1.txt file2.txt) | uniq -uWie bei Ihrer Lösung funktioniert dies jedoch nur, wenn die Pattern-Datei tatsächlich keine regulären Metazeichen enthält.
rici
@rici, das ist ein sehr guter Punkt
iruvar
2
Verbesserung:grep -oFf file1.txt file2.txt | sort file1.txt - | uniq -u
Stéphane Chazelas
10

Du könntest es machen mit awk:

awk '
  NR == FNR {w[$0]; next}
  {for (i in w) if (index($0,i)) delete w[i]}
  END {for (i in w) print i}' file1.txt file2.txt

Durch die Verwendung von indexsuchen wir nach Teilzeichenfolgen, anstatt reguläre Ausdrücke abzugleichen.

Da wir das Wort aus dem Array löschen, sobald wir eine Übereinstimmung finden, vermeiden wir unnötige Suchen.

Stéphane Chazelas
quelle
1
Ich würde nur diesen einen akzeptieren. Es ruft keine O (n log n) -Sortierung auf und schlägt nicht seltsam fehl, wenn die Muster Regex-Metazeichen enthalten, und kann zur Unterstützung von Regexen erweitert werden.
Kaz
Ich kann nicht glauben, dass das einfache Auswerten w[$0]den Nebeneffekt hat, den Schlüssel zum Array hinzuzufügen.
Kaz
1
@Kaz, ja, das kann verwirrend sein, und Sie finden viele Skripte, die nicht wissentlich Array-Elemente zuweisen, indem Sie dies beispielsweise if (a[$1])anstelle von tun if ($1 in a). Es ist der Fall von jeder awkder ursprünglichen einschließlich awkund nawk, aber im Standard gestern suchen, konnte ich nicht finden spezifiziert.
Stéphane Chazelas
1
@Kaz Hier ist das POSIX - Zitat: „Die Anwendung stellt sicher , dass ein Multi-dimensionierte Index mit der verwendeten in Operator klammert Die. In Bediener, die Tests für das Vorhandensein eines bestimmten Array - Elements, sind nicht Sache dieses Element bestehen zu Any. Ein anderer Verweis auf ein nicht vorhandenes Array-Element erstellt es automatisch. " Sie finden es, indem Sie von hier aus einen oder zwei Absätze nach oben scrollen .
JW013
1
Solange file1diese Lösung nicht sehr groß ist (für einen Wert von sehr groß), würde ich sie vorziehen, da sie keine Sortierung erfordert file2und voraussichtlich viel effizienter ist.
JW013