Jeg vil gerne få multimønsteret match med implicit OG mellem mønstre, dvs. svarer til at køre flere greps i en sekvens:

grep pattern1 | grep pattern2 | ... 

Så hvordan konverteres det til noget lignende?

grep pattern1 & pattern2 & pattern3 

Jeg vil gerne bruge single grep, fordi jeg bygger argumenter dynamisk, så alt skal passe i en streng. Brug af filter er systemfunktion, ikke grep, så det er ikke et argument for det.


Forveksl ikke dette spørgsmål med:

grep "pattern1\|pattern2\|..." 

Dette er en ELLER matchning med flere mønstre.

Kommentarer

Svar

agrep kan gøre det med denne syntaks:

agrep "pattern1;pattern2" 

Med GNU grep, når den er bygget med med PCRE-understøttelse kan du gøre:

grep -P "^(?=.*pattern1)(?=.*pattern2)" 

Med ast grep :

grep -X ".*pattern1.*&.*pattern2.*" 

(tilføjer .* s som <x>&<y> matcher strenge, der matcher både <x> og <y> nøjagtigt , a&b ville aldrig matche, da der ikke er sådan en streng, der kan være både a og b på samme tid).

Hvis mønstrene ikke overlapper hinanden, kan du muligvis også gøre:

grep -e "pattern1.*pattern2" -e "pattern2.*pattern1" 

Den bedste bærbare måde er sandsynligvis med awk som allerede nævnt:

awk "/pattern1/ && /pattern2/" 

Med sed:

sed -e "/pattern1/!d" -e "/pattern2/!d" 

Vær opmærksom på, at alle disse har forskellige syntaks for regulært udtryk.

Kommentarer

  • agrep syntaksen fungerer ikke for mig … hvilken version blev den introduceret i?
  • @Raman 2.04 fra 1992 havde den allerede. Jeg ‘ har ingen grund til at tro, at det ikke var ‘ der fra starten. Nyere (efter 1992) versioner af agrep kan findes inkluderet i glimt / webglimpse . Muligvis har du en anden implementering. Jeg havde dog en fejl i ast-grep-versionen, men indstillingen for augmented regexps er -X, ikke -A.
  • @St é phaneChazelas Tak, jeg har agrep 0.8.0 på Fedora 23. Dette ser ud til være en anden agrep end den, du henviser til.
  • @Raman, din lyder som TRE agrep .
  • @Techiee eller bare awk '/p1/ && /p2/ {n++}; END {print 0+n}'

Svar

Du har ikke angivet grep-version, dette er vigtigt. Nogle regexp-motorer tillader flere matchende grupperinger af OG ved hjælp af “& “men dette er ikke-standard og ikke-bærbar funktion. Men i det mindste understøtter GNU grep ikke dette.

OTOH du kan simpelthen erstatte grep med sed, awk, perl osv. . (opført i rækkefølge efter vægtforøgelse). Med awk ser kommandoen ud som

 awk "/regexp1/ && /regexp2/ && /regexp3/ { print; }" 

, og den kan konstrueres til at angives på kommandolinjen på en nem måde.

Kommentarer

  • Bare husk at awk bruger ERE ‘ s, f.eks. svarende til grep -E i modsætning til BRE ‘ s, som almindelig grep bruger.
  • awk ‘ s regexes kaldes EREer, men faktisk ‘ er lidt idiosynkratisk. Her er sandsynligvis flere detaljer, end nogen holder af: wiki.alpinelinux.org/wiki/Regex
  • Tak, grep 2.7.3 ( openSUSE). Jeg opstemte dig, men jeg holder spørgsmål åbent et stykke tid, måske er der noget trick for grep (ikke at jeg ikke kan lide awk – det er bare bedre at vide mere).
  • Standardhandlingen er at udskrive den matchende linje, så { print; } -delen er ikke ‘ t virkelig nødvendig eller nyttig her.

Svar

Hvis patterns indeholder et mønster pr. linje, du kan gøre noget som dette:

 awk "NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1" patterns -  

Eller dette matcher understrenge i stedet for almindelige udtryk:

 awk "NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1" patterns -  

For at udskrive alt i stedet for ingen linjer af input i hvis patterns er tom, skal du erstatte NR==FNR med FILENAME==ARGV[1] eller med ARGIND==1 i gawk.

Disse funktioner udskriver linjerne i STDIN, som indeholder hver streng, der er angivet som et argument som en understreng. ga står for grep all og gai ignorerer store og små bogstaver.

 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 "$@") -; }  

Kommentarer

  • skarpt svar, der adresserer flere anvendelsessager og fungerer (verificeret på macos)

Svar

grep pattern1 | grep pattern2 | ...

Jeg vil gerne bruge single grep, fordi jeg bygger argumenter dynamisk , så alt skal passe i en streng

Det er faktisk muligt at opbygge rørledningen dynamisk (uden at ty til eval):

 # 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  

Det er sandsynligvis ikke en særlig effektiv løsning.

Kommentarer

  • Brug enten chained-grep() eller function chained-grep men ikke function chained-grep(): unix.stackexchange.com/questions/73750/…
  • Kan du beskrive, hvad tricket er? Kan du føje det til svaret ( uden ” Rediger: “, ” Opdatering: ” eller lignende) ved at redigere det ?
  • Omformuleret svaret for at gøre tricket klarere (dvs.: opbygge en shell-rørledning dynamisk)

Svar

git grep

Her er syntaksen ved hjælp af git grep kombinerer flere mønstre ved hjælp af boolske udtryk:

git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3 

Ovenstående kommando udskriver linjer, der matcher alle mønstre på én gang.

--no-index Søg efter filer i den aktuelle mappe, der ikke administreres af Git.

Marker man git-grep for hjælp.

Se også:

For ELLER operation, se:

Kommentarer

  • Fremragende svar. Tak.

Svar

Her er min optagelse, og dette fungerer for ord i flere linjer:

Brug find . -type f efterfulgt af lige så mange
-exec grep -q "first_word" {} \;
og det sidste søgeord med
-exec grep -l "nth_word" {} \;

-q stille / lydløs
-l vis filer med matches

Følgende returnerer en liste med filnavne med ordene “kanin” og “hul” i:
find . -type f -exec grep -q "rabbit" {} \; -exec grep -l "hole" {} \;

Kommentarer

  • Hvis du ser nøje, kan du bare lære, at dette ikke er den funktion, som spørgsmålet beder om.

Svar

ripgrep

Her er eksemplet ved hjælp af rg :

rg -N "(?P<p1>.*pattern1.*)(?P<p2>.*pattern2.*)(?P<p3>.*pattern3.*)" file.txt 

Det er et af de hurtigste grepping-værktøjer, da det er bygget oven på Rusts regex-motor , der bruger endelige automata, SIMD og aggressive bogstavelige optimeringer for at gøre søgning meget hurtig.

Se også relateret funktionsanmodning på GH-875 .

Svar

For at finde alle ordene (eller mønstrene) kan du køre grep i en for -sløjfe. Den største fordel her er at søge fra en liste over regulære udtryk .

Et rigtigt eksempel:

# 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 

Lad os nu køre det på denne fil:

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! 

Kommentarer

  • Din logik er defekt – jeg bad om ALL operatør, din kode fungerer som OR operator, ikke AND. Og btw. For det (OR) er meget lettere løsning givet lige i spørgsmålet.
  • @greenoldman Logikken er enkel: For vil løkke på ALLE ord / mønstre på listen, og hvis den findes i filen – vil udskrive den. Så fjern den anden, hvis du ikke ‘ ikke har brug for handling, hvis ordet ikke blev fundet.
  • Jeg forstår din logik såvel som mit spørgsmål – jeg spurgte om AND operatør, hvilket betyder at filen kun er et positivt hit, hvis det matcher mønster A og mønster B og mønster C og … AND I dit tilfælde er filen et positivt hit, hvis den ma tches mønster A eller mønster B eller … Ser du forskellen nu?
  • @greenoldman ikke sikker på, hvorfor du mener, at denne løkke ikke kontrollerer OG-tilstand for alle mønstre? Så jeg ‘ har redigeret mit svar med et rigtigt eksempel: Det vil søge i filen efter alle regex af listen, og på den første, der mangler – vil afslutte med fejl.
  • Du har det lige foran dine øjne, du har en positiv match lige efter at den første kamp er udført. Du skal have ” samle ” alle resultater og beregne AND på dem. Derefter skal du omskrive scriptet for at køre på flere filer – så måske indser du, at spørgsmålet allerede er besvaret, og dit forsøg bringer ikke noget til bordet, undskyld.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *