Ich versuche, grep
nur Zeilen anzuzeigen, die eines der beiden Wörter enthalten, wenn nur eines in der Zeile erscheint, aber nicht, wenn sie sich in derselben Zeile befinden.
Bisher habe ich es versucht grep pattern1 | grep pattern2 | ...
, aber nicht das erwartete Ergebnis erzielt.
[a-z][a-z0-9]\(,7\}\(\.[a-z0-9]\{,3\}\)+
? (2) Was ist, wenn eines der Wörter / Muster mehr als einmal in einer Zeile erscheint (und das andere nicht)? Entspricht das dem Wort, das einmal vorkommt, oder zählt es als Mehrfachvorkommen?Antworten:
Ein anderes Werkzeug als
grep
der richtige Weg.Unter Verwendung von Perl wäre der Befehl beispielsweise:
perl -ne
Führt den Befehl aus, der über jede Zeile von stdin ausgegeben wird. In diesem Fall wird die Zeile gedruckt, wenn sie übereinstimmt/pattern1/ xor /pattern2/
, oder mit anderen Worten , wenn sie mit einem Muster übereinstimmt, jedoch nicht mit dem anderen (exklusiv oder).Dies funktioniert für das Muster in jeder Reihenfolge und sollte eine bessere Leistung aufweisen als mehrere Aufrufe von
grep
und ist auch weniger tippend.Oder noch kürzer mit awk:
oder für Versionen von awk, die nicht haben
xor
:quelle
xor
nur in GNU Awk?/pattern1/+/pattern2/==1
ir ersetzenxor
fehlt.\b
) in die Muster selbst einfügen, dh\bword\b
.Mit GNU
grep
können Sie beide Wörter übergebengrep
und dann die Zeilen entfernen, die beide Muster enthalten.quelle
Versuche es mit
egrep
quelle
grep -e foo -e bar | grep -v -e 'foo.*bar' -e 'bar.*foo'
Direct invocation as either egrep or fgrep is deprecated
- prefergrep -E
-f
und-e
Optionen haben sollte , obwohl die älterenegrep
undfgrep
noch eine Weile unterstützt werden.grep
(das Stützen-F
,-E
,-e
,-f
wie POSIX erfordert) ist in/usr/xpg4/bin
. Die Versorgungsunternehmen in/bin
sind veraltet.Mit
grep
Implementierungen, die perlähnliche reguläre Ausdrücke (wiepcregrep
oder GNU oder ast-opengrep -P
) unterstützen, können Sie dies in einemgrep
Aufruf tun :Das heißt die Zeilen finden, die
pat1
aber nicht passenpat2
, oderpat2
doch nichtpat1
.(?=...)
und(?!...)
sind jeweils vorausschauende und negative vorausschauende Betreiber. Technisch betrachtet, sucht das Obige nach dem Anfang des Themas (^
), vorausgesetzt, es wird gefolgt.*pat1
und nicht gefolgt.*pat2
, oder dasselbe mitpat1
undpat2
umgekehrt.Das ist suboptimal für Linien, die beide Muster enthalten, da sie dann zweimal gesucht würden. Sie könnten stattdessen fortgeschrittenere Perl-Operatoren verwenden, wie:
(?(1)yespattern|nopattern)
Übereinstimmungen mit,yespattern
wenn die1
st- Erfassungsgruppe (()
oben leer ) übereinstimmt,nopattern
andernfalls. Wenn dies()
zutrifft, bedeutetpat1
dies , dass es nicht zutrifft, und wir suchen nachpat2
(positiver Blick nach vorn) und wir suchen nach nichts anderempat2
(negativer Blick nach vorn).Mit
sed
könnte man es schreiben:quelle
grep: the -P option only supports a single pattern
, zumindest auf jedem System, auf das ich Zugriff habe. +1 für Ihre zweite Lösung.grep
.pcregrep
und ast-open grep haben dieses problem nicht. Ich habe das Multiple-e
durch den alternierenden RE-Operator ersetzt, daher sollte esgrep
jetzt auch mit GNU funktionieren .In Booleschen Begriffen suchen Sie nach A xor B, das als geschrieben werden kann
(A und nicht B)
oder
(B und nicht A)
Da in Ihrer Frage nicht erwähnt wird, dass Sie sich mit der Reihenfolge der Ausgabe befassen, solange die übereinstimmenden Zeilen angezeigt werden, ist die Boolesche Erweiterung von A xor B in grep ziemlich einfach:
quelle
sort | uniq
.Für das folgende Beispiel:
Dies kann rein mit getan werden
grep -E
,uniq
undwc
.Wenn
grep
es mit regulären Perl-Ausdrücken kompiliert wurde, können Sie beim letzten Vorkommen eine Übereinstimmung finden, anstatt eine Pipe anuniq
folgende Stellen ausführen zu müssen :Ergebnis ausgeben:
Ein Einzeiler:
Wenn Sie das Muster nicht hart codieren möchten, können Sie es mit einer Funktion automatisieren, indem Sie es mit einem variablen Satz von Elementen zusammensetzen.
Dies kann auch nativ in Bash als Funktion ohne Pipes oder zusätzliche Prozesse erfolgen, ist jedoch aufwändiger und liegt wahrscheinlich außerhalb des Rahmens Ihrer Frage.
quelle
Big apple\n
und enthältpear-shaped\n
, sollte die Ausgabe beide Zeilen enthalten. Ihre Lösung würde mit 2 bewertet; Die Langfassung würde "Beide Wörter stimmen überein" (was eine Antwort auf die falsche Frage ist) und die Kurzfassung würde überhaupt nichts aussagen. (3) Ein Vorschlag: Die Verwendung von-o
hier ist eine wirklich schlechte Idee, da hier die Zeilen ausgeblendet werden, die die Übereinstimmungen enthalten, sodass Sie nicht sehen können, wann beide Wörter in derselben Zeile erscheinen. … (Fortsetzung)uniq
/sort -u
und der ausgefallene reguläre Perl-Ausdruck, der nur dem letzten Vorkommen in jeder Zeile entspricht, ergeben keine wirklich nützliche Antwort auf diese Frage. Aber selbst wenn dies der Fall wäre, wäre es immer noch eine schlechte Antwort, da Sie nicht erklären, wie sie zur Beantwortung der Frage beitragen. ( Ein Beispiel für eine gute Erklärung finden Sie in der Antwort von Stéphane Chazelas .)