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

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 andere agrep 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 von grep -E im Gegensatz zu den BRE ‚, die von grep 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 "[email protected]") -; } gai(){ awk "FILENAME==ARGV[1]{a[tolower($0)];next}{for(i in a)if(!index(tolower($0),i))next}1" <(printf %s\\n "[email protected]") -; }  

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 "[email protected]" } 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() oder function chained-grep, aber nicht function 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:

Informationen zum ODER -Betrieb finden Sie unter:

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 als OR -Operator, nicht als AND. 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.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.