Drucken Sie unvergleichliche Muster mit grep und Mustern aus der Datei

14

patterns.txt:

"BananaOpinion"
"ExitWarning"
"SomeMessage"
"Help"
"Introduction"
"MessageToUser"

Strings.xml

<string name="Introduction">One day there was an apple that went to the market.</string>
<string name="BananaOpinion">Bananas are great!</string>
<string name="MessageToUser">We would like to give you apples, bananas and tomatoes.</string>

Erwartete Ausgabe:

"ExitWarning"
"SomeMessage"
"Help" 

Wie drucke ich die Begriffe aus, in patterns.txtdenen sich nichts befindet Strings.xml? Ich kann die abgestimmt / unerreichten Drucklinien in Strings.xml, aber wie drucke ich die unerreichten Muster ? Ich benutze ggrep (GNU grep) Version 2.21, bin aber offen für andere Tools. Entschuldigung, wenn dies ein Duplikat einer anderen Frage ist, die ich nicht finden konnte.

Nate Cook
quelle

Antworten:

24

Sie können grep -onur das passende Teil drucken und das Ergebnis für eine Sekunde als Muster für grep -vdie Originaldatei patterns.txtverwenden:

grep -oFf patterns.txt Strings.xml | grep -vFf - patterns.txt

In diesem speziellen Fall können Sie jedoch auch join+ verwenden sort:

join -t\" -v1 -j2 -o 1.1 1.2 1.3 <(sort -t\" -k2 patterns.txt) <(sort -t\" -k2 strings.xml)
don_crissti
quelle
das ist ganz elegant .. schlau!
XXL
Wenn Sie mehrere Eingabedateien haben (z. B. Strings1.xmlund Strings2.xml), benötigen Sie auch das -hFlag auf dem ersten Grep.
Jayhendren
@ Jayhendren - ja, aber nicht alle grepunterstützen diese Option. Wenn Sie mehrere Eingabedateien haben, verstehe ich nicht, warum Sie sie nicht catalle haben können und leiten Sie das Ergebnis an grep.
don_crissti
5

Der beste Ansatz ist wahrscheinlich der, den @don_crissti vorgeschlagen hat. Hier ist eine Variation desselben Themas:

$ grep -vf <(grep -Po 'name=\K.+?"' Strings.xml) patterns.txt
"ExitWarning"
"SomeMessage"
"Help"

Dies ist im Grunde das Gegenteil von @ don_crisstis Ansatz. Es verwendet grep mit Perl-kompatiblen regulären Ausdrücken ( -P) und dem -oSchalter, um nur den passenden Teil der Zeile zu drucken. Dann sucht name=und verwirft der Regex ( \K) und sucht dann nach einem oder mehreren Zeichen bis zum ersten "( .+?"). Dies ergibt die Liste der in der String.txtDatei vorhandenen Muster, die dann als Eingabe an ein umgekehrtes grep ( grep -v) unter Verwendung von process substitution ( <(command)) übergeben werden.

terdon
quelle
2

Ich würde cutwahrscheinlich verwenden. Das heißt, wenn Sie, wie es scheint, wissen, wo Sie die angeführte Zeichenfolge erwarten können, nach der Sie suchen.

Wenn ich mache:

{   cut  -sd\" -f2 |
    grep -vFf- pat
}   <<\IN
#   <string name="Introduction">One day there was an apple that went to the market.</string>
#   <string name="BananaOpinion">Bananas are great!</string>
#   <string name="MessageToUser">We would like to give you apples, bananas and tomatoes.</string>
IN

... nachdem ich meine eigene Kopie Ihres Beispiels patterns.txtin patgespeichert und den obigen Befehl ausgeführt habe, lautet die Ausgabe:

"ExitWarning"
"SomeMessage"
"Help"

cutDrucke auf stdout nur die zweite "doppelte Anführungszeichen -delimited -field für jeden Begrenzer abgestimmte Eingabezeile und -suppresses alle anderen.

Was cuttatsächlich gedruckt wird, grepist:

Introduction
BananaOpinion
MessageToUser

grepsucht seine benannte Datei - Operanden für Linien , die -vdie nicht übereinstimmen -Fixed Strings in seine -stdin Muster -file.

Wenn Sie sich darauf verlassen können, dass das "zweitbegrenzte Feld übereinstimmt, dann ist dies definitiv eine Optimierung gegenüber dem grep -PErl-Modus, indem Sie nur -Ffestgelegte Zeichenfolgen und nur winzige Teile davon zusammenfügen, da cutdies das schwere Heben bewirkt - und es geht schnell .

mikeserv
quelle
1
for p in $(cat patterns.txt); do if ! grep $p strings.xml &>/dev/null; then echo $p; fi; done

Es ist leicht zu verstehen, hat aber die Ausfallzeit, mehrere grep-Prozesse zu erzeugen, einen für jede Zeile in patterns.txt.

user277493
quelle
0

Eine andere Möglichkeit besteht darin, patterns.txt und Strings.xml in eine Liste aufzunehmen und nach eindeutigen Zeilen zu suchen

cat patterns.txt Strings.xml | grep -oFf patterns.txt | sort | uniq -u

Erläuterung:

cat patterns.txt Strings.xmlfasst alles in einer Liste zusammen. grep -oFf patterns.txtEntfernt den Müll in jeder Zeile. sortselbsterklärend. sortiere alle Zeilen. uniq -udruckt nur einzelne Zeilen.

erik80
quelle