Ich möchte die Multi-Pattern-Übereinstimmung mit implizitem UND zwischen Mustern, dh gleichbedeutend mit dem Ausführen mehrerer Greps in einer Sequenz:
grep pattern1 | grep pattern2 | ...
Wie konvertiere ich es in so etwas wie?
grep pattern1 & pattern2 & pattern3
Ich möchte Single Grep verwenden, da ich Argumente dynamisch erstelle, sodass alles in eine Zeichenfolge passen muss. Die Verwendung des Filters ist eine Systemfunktion, keine grep, daher kein Argument dafür.
Verwechseln Sie diese Frage nicht mit:
grep "pattern1\|pattern2\|..."
Dies ist eine ODER Multi-Pattern-Übereinstimmung.
Kommentare
- Ähnlich: Alle Muster aus der Datei gleichzeitig abgleichen
- Ähnliche Frage zu SO : Überprüfen Sie, ob in einer Datei mehrere Zeichenfolgen oder reguläre Ausdrücke vorhanden sind
- Wenn Sie ‚ suchen Suchen Sie für die grep-Syntax für “ Zeilen, die
foo
enthalten, und Zeilen, diebar
“ siehe Verwenden von grep für mehrere Suchmuster
Antwort
agrep
kann dies mit folgender Syntax tun:
agrep "pattern1;pattern2"
Mit GNU grep
, wenn w Mit PCRE-Unterstützung können Sie Folgendes tun:
grep -P "^(?=.*pattern1)(?=.*pattern2)"
Mit ast grep
:
grep -X ".*pattern1.*&.*pattern2.*"
(Hinzufügen von .*
s als <x>&<y>
stimmt mit Zeichenfolgen überein, die sowohl mit <x>
als auch mit <y>
genau übereinstimmen, a&b
würde niemals übereinstimmen, da es keine solche Zeichenfolge gibt, die sowohl a
als auch b
zur gleichen Zeit).
Wenn sich die Muster nicht überlappen, können Sie möglicherweise auch Folgendes tun:
grep -e "pattern1.*pattern2" -e "pattern2.*pattern1"
Der beste tragbare Weg ist wahrscheinlich mit awk
, wie bereits erwähnt:
awk "/pattern1/ && /pattern2/"
Mit sed
:
sed -e "/pattern1/!d" -e "/pattern2/!d"
Bitte beachten Sie, dass alle diese eine andere Syntax für reguläre Ausdrücke haben.
Kommentare
- Die Syntax
agrep
funktioniert nicht Ich … in welcher Version wurde es eingeführt? - @Raman 2.04 von 1992 hatte es bereits. Ich ‚ habe keinen Grund zu der Annahme, dass es ‚ von Anfang an nicht da war. Neuere (nach 1992) Versionen von
agrep
sind in glimpse / webglimpse enthalten. Möglicherweise haben Sie eine andere Implementierung. Ich hatte jedoch einen Fehler bei der ast-grep-Version. Die Option für erweiterte reguläre Ausdrücke lautet-X
und nicht-A
. - @St é phaneChazelas Danke, ich habe
agrep
0.8.0 auf Fedora 23. Dies scheint zu sein Seien Sie eine andereagrep
als die, auf die Sie verweisen. - @Raman, Ihre klingt wie TRE
agrep
. - @Techiee oder einfach
awk '/p1/ && /p2/ {n++}; END {print 0+n}'
Antwort
Sie haben keine grep-Version angegeben, dies ist wichtig. Einige Regexp-Engines erlauben mehrere Übereinstimmungen, die von AND mit „& „, aber dies ist keine Standard- und nicht portable Funktion. Aber zumindest unterstützt GNU grep dies nicht.
OTOH Sie können grep einfach durch sed, awk, perl usw. ersetzen (in der Reihenfolge der Gewichtszunahme aufgeführt). Mit awk würde der Befehl wie folgt aussehen:
awk "/regexp1/ && /regexp2/ && /regexp3/ { print; }"
und kann so konstruiert werden, dass er auf einfache Weise in der Befehlszeile angegeben wird.
Kommentare
- Denken Sie daran, dass
awk
ERE ‚ verwendet, z das Äquivalent vongrep -E
im Gegensatz zu den BRE ‚, die vongrep
verwendet werden. -
awk
‚ s reguläre Ausdrücke werden EREs genannt, aber tatsächlich ‚ ist etwas eigenwillig. Hier sind wahrscheinlich mehr Details, als sich irgendjemand interessiert: wiki.alpinelinux.org/wiki/Regex - Vielen Dank, grep 2.7.3 ( openSUSE). Ich habe dich positiv bewertet, aber ich werde die Frage für eine Weile offen halten, vielleicht gibt es einen Trick für grep (nicht, dass ich
awk
nicht mag – einfach mehr zu wissen ist besser). - Die Standardaktion besteht darin, die übereinstimmende Zeile zu drucken, damit der Teil
{ print; }
‚ hier nicht wirklich notwendig oder nützlich ist.
Antwort
Wenn patterns
ein Muster pro Zeile enthält, Sie können Folgendes tun:
awk "NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1" patterns -
Oder dies entspricht Teilzeichenfolgen anstelle von regulären Ausdrücke:
awk "NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1" patterns -
Zum Drucken aller statt keiner Zeilen der Eingabe in der Wenn patterns
leer ist, ersetzen Sie NR==FNR
durch FILENAME==ARGV[1]
oder durch ARGIND==1
in gawk
.
Diese Funktionen drucken die Zeilen von STDIN, die jede als Argument angegebene Zeichenfolge als Teilzeichenfolge enthalten. ga
steht für grep all und gai
ignoriert Groß- und Kleinschreibung.
ga(){ awk "FILENAME==ARGV[1]{a[$0];next}{for(i in a)if(!index($0,i))next}1" <(printf %s\\n "$@") -; } gai(){ awk "FILENAME==ARGV[1]{a[tolower($0)];next}{for(i in a)if(!index(tolower($0),i))next}1" <(printf %s\\n "$@") -; }
Kommentare
- klare Antwort, die mehrere Anwendungsfälle anspricht und funktioniert (auf Macos überprüft)
Antwort
grep pattern1 | grep pattern2 | ...
Ich möchte Single Grep verwenden, da ich Argumente dynamisch erstelle, sodass alles in eine Zeichenfolge passen muss.
Es ist tatsächlich möglich, die Pipeline dynamisch zu erstellen (ohne auf eval
zurückzugreifen):
# Executes: grep "$1" | grep "$2" | grep "$3" | ... function chained-grep { local pattern="$1" if [[ -z "$pattern" ]]; then cat return fi shift grep -- "$pattern" | chained-grep "$@" } cat something | chained-grep all patterns must match order but matter dont
Es ist jedoch wahrscheinlich keine sehr effiziente Lösung.
Kommentare
- Verwenden Sie entweder
chained-grep()
oderfunction chained-grep
, aber nichtfunction chained-grep()
: unix.stackexchange.com/questions/73750/… - Können Sie beschreiben, was der Trick ist? Können Sie es der Antwort hinzufügen ( ohne “ Bearbeiten: „, “ Update: “ oder ähnlich) durch Bearbeiten ?
- Die Antwort wurde neu formuliert, um den Trick klarer zu machen (dh: eine Shell-Pipeline dynamisch erstellen).
Antwort
git grep
Hier ist die Syntax mit git grep
Kombinieren mehrerer Muster mit Booleschen Ausdrücken:
git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3
Mit dem obigen Befehl werden Zeilen gedruckt, die mit allen Mustern gleichzeitig übereinstimmen.
--no-index
Durchsucht Dateien im aktuellen Verzeichnis, die nicht von Git verwaltet werden.
Überprüfen Sie man git-grep
um Hilfe.
Siehe auch:
- Wie geht es uns? e grep passend zu string1 UND string2?
- Überprüfen Sie, ob in einer Datei alle mehreren Strings oder regulären Ausdrücke vorhanden sind .
Informationen zum ODER -Betrieb finden Sie unter:
- Wie greife ich nach mehreren Muster mit Muster mit einem Pipe-Zeichen?
- Grep: Hinzufügen eines “ ODER “ Bedingung?
Kommentare
- Hervorragende Antwort. Vielen Dank.
Antwort
Hier ist meine Einstellung, und dies funktioniert für Wörter in mehreren Zeilen:
Verwenden Sie find . -type f
gefolgt von so vielen
-exec grep -q "first_word" {} \;
und dem letzten Schlüsselwort mit
-exec grep -l "nth_word" {} \;
-q
leise / leise
-l
Dateien anzeigen mit Übereinstimmungen
Die folgende Liste enthält Dateinamen mit den Wörtern „Kaninchen“ und „Loch“:
find . -type f -exec grep -q "rabbit" {} \; -exec grep -l "hole" {} \;
Kommentare
- Wenn Sie genau hinschauen, werden Sie möglicherweise feststellen, dass dies nicht die Funktionalität ist, nach der die Frage fragt.
Antwort
ripgrep
Hier ist das Beispiel mit rg
:
rg -N "(?P<p1>.*pattern1.*)(?P<p2>.*pattern2.*)(?P<p3>.*pattern3.*)" file.txt
Es ist eines der schnellsten Grepping-Tools, da es auf Rusts Regex-Engine , die endliche Automaten, SIMD und aggressive Literaloptimierungen verwendet, um die Suche sehr schnell zu machen.
Siehe auch die entsprechende Funktionsanforderung unter GH-875 .
Antwort
Um alle aller Wörter (oder Muster) zu finden, können Sie grep
in einer for
-Schleife ausführen. Der Hauptvorteil hierbei ist die Suche aus einer Liste regulärer Ausdrücke .
Ein echtes Beispiel:
# File "search_all_regex_and_error_if_missing.sh" find_list="\ ^a+$ \ ^b+$ \ ^h+$ \ ^d+$ \ " for item in $find_list; do if grep -E "$item" file_to_search_within.txt then echo "$item found in file." else echo "Error: $item not found in file. Exiting!" exit 1 fi done
Lassen Sie es uns jetzt in dieser Datei ausführen:
hhhhhhhhhh aaaaaaa bbbbbbbbb ababbabaabbaaa ccccccc dsfsdf bbbb cccdd aa caa
$ ./search_all_regex_and_error_if_missing.sh aaaaaaa aa ^a+$ found in file. bbbbbbbbb bbbb ^b+$ found in file. hhhhhhhhhh ^h+$ found in file. Error: ^d+$ not found in file. Exiting!
Kommentare
- Ihre Logik ist fehlerhaft – ich habe nach
ALL
-Operator, Ihr Code funktioniert alsOR
-Operator, nicht alsAND
. Und übrigens dafür (OR
) ist eine viel einfachere Lösung, die direkt in der Frage angegeben wird. - @greenoldman Die Logik ist einfach: Die for will -Schleife für ALLE Wörter / Muster in der Liste, und wenn es in der Datei gefunden wird, wird es gedruckt. Entfernen Sie also einfach das else, wenn Sie ‚ keine Aktion benötigen, falls das Wort nicht gefunden wurde.
- Ich verstehe Ihre Logik sowie meine Frage – ich habe nach dem Operator
AND
gefragt, was bedeutet, dass die Datei nur dann ein positiver Treffer ist, wenn sie mit Muster A und Muster übereinstimmt B und Muster C und …AND
In Ihrem Fall ist die Datei positiv getroffen, wenn sie ma tches Muster A oder Muster B oder … Sehen Sie jetzt den Unterschied? - @greenoldman Sie sind sich nicht sicher, warum diese Schleife Ihrer Meinung nach nicht die UND-Bedingung für alle Muster überprüft? Also habe ich ‚ meine Antwort mit einem echten Beispiel bearbeitet: Es wird in der Datei nach allen regulären Ausdrücken der Liste suchen und bei der ersten, die fehlt – wird mit einem Fehler beendet.
- Sie haben es direkt vor Ihren Augen, Sie haben eine positive Übereinstimmung, gleich nachdem die erste Übereinstimmung ausgeführt wurde. Sie sollten “ “ alle Ergebnisse sammeln und
AND
darauf berechnen. Dann sollten Sie das Skript so umschreiben, dass es auf mehreren Dateien ausgeführt wird. Dann stellen Sie möglicherweise fest, dass die Frage bereits beantwortet wurde und Ihr Versuch leider nichts auf den Tisch bringt.