Jeg vil gjerne få flertallsmønsteret med implisitt OG mellom mønstre, dvs. tilsvarer å kjøre flere greps i en sekvens:

grep pattern1 | grep pattern2 | ... 

Så hvordan konverterer du det til noe sånt?

grep pattern1 & pattern2 & pattern3 

Jeg vil gjerne bruke single grep fordi jeg bygger argumenter dynamisk, så alt må passe i en streng. Å bruke filter er systemfunksjon, ikke grep, så det er ikke et argument for det.


Ikke forveksle dette spørsmålet med:

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

Dette er en ELLER flertallsmønster.

Kommentarer

Svar

agrep kan gjøre det med denne syntaksen:

agrep "pattern1;pattern2" 

Med GNU grep, når den er bygd m Med PCRE-støtte kan du gjøre:

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

Med ast grep :

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

(legger til .* s som <x>&<y> samsvarer med strenger som samsvarer med både <x> og <y> nøyaktig , a&b vil aldri matche siden det ikke er noen streng som kan være både a og b samtidig).

Hvis mønstrene ikke overlapper hverandre, kan det hende du også kan gjøre:

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

Den beste bærbare måten er sannsynligvis med awk som allerede nevnt:

awk "/pattern1/ && /pattern2/" 

Med sed:

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

Vær oppmerksom på at alle disse har forskjellig syntaks med regulært uttrykk.

Kommentarer

  • agrep syntaksen fungerer ikke for meg … hvilken versjon ble den introdusert i?
  • @Raman 2.04 fra 1992 hadde den allerede. Jeg ‘ har ingen grunn til å tro at det ikke var ‘ t der fra starten. Nyere (etter 1992) versjoner av agrep finner du inkludert i glimt / webglimpse . Muligens har du en annen implementering. Jeg hadde en feil med ast-grep-versjonen, men alternativet for augmented regexps er -X, ikke -A.
  • @St é phaneChazelas Takk, jeg har agrep 0.8.0 på Fedora 23. Dette ser ut til vær en annen agrep enn den du refererer til.
  • @Raman, din høres ut som TRE agrep .
  • @Techiee, eller bare awk '/p1/ && /p2/ {n++}; END {print 0+n}'

Svar

Du spesifiserte ikke grep-versjon, dette er viktig. Noen regexp-motorer tillater flere samsvar, gruppert av OG ved hjelp av «& «men dette er ikke-standard og ikke-bærbar funksjon. Men i det minste støtter ikke GNU grep dette.

OTOH du kan ganske enkelt erstatte grep med sed, awk, perl, etc . (oppført i rekkefølge etter vektøkning). Med awk vil kommandoen se ut som

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

, og den kan konstrueres for å spesifiseres på kommandolinjen på en enkel måte.

Kommentarer

  • Bare husk at awk bruker ERE ‘ s, f.eks. tilsvarer grep -E, i motsetning til BRE ‘ s som vanlig grep bruker.
  • awk ‘ s regexer kalles EREer, men faktisk ‘ er litt idiosynkratisk. Her er sannsynligvis flere detaljer enn noen bryr seg om: wiki.alpinelinux.org/wiki/Regex
  • Takk, grep 2.7.3 ( openSUSE). Jeg oppstemte deg, men jeg vil holde spørsmålet åpent en stund, kanskje det er noe triks for grep (ikke det at jeg ikke liker awk – bare å vite mer er bedre).
  • Standardhandlingen er å skrive ut den samsvarende linjen slik at { print; } -delen ikke er ‘ t virkelig nødvendig eller nyttig her.

Svar

Hvis patterns inneholder ett mønster per linje, du kan gjøre noe sånt som dette:

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

Eller dette samsvarer med understrenger i stedet for vanlig uttrykk:

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

For å skrive ut alt i stedet for ingen linjer av inngangen i hvis patterns er tom, erstatt NR==FNR med FILENAME==ARGV[1], eller med ARGIND==1 i gawk.

Disse funksjonene skriver ut linjene i STDIN som inneholder hver streng spesifisert som et argument som en understreng. ga står for grep all og gai ignorerer tilfelle.

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

Kommentarer

  • skarpt svar som adresserer flere brukssaker og fungerer (bekreftet på macos)

Svar

grep pattern1 | grep pattern2 | ...

Jeg vil gjerne bruke enkelt grep fordi jeg bygger argumenter dynamisk , så alt må passe i en streng

Det er faktisk mulig å bygge rørledningen dynamisk (uten å 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 "[email protected]" } cat something | chained-grep all patterns must match order but matter dont  

Det er sannsynligvis ikke en veldig effektiv løsning.

Kommentarer

  • Bruk enten chained-grep() eller function chained-grep men ikke function chained-grep(): unix.stackexchange.com/questions/73750/…
  • Kan du beskrive hva kunsten er? Kan du legge det til svaret ( uten » Rediger: «, » Oppdatering: «, eller lignende) ved å redigere den ?
  • Omformulert svaret for å gjøre trikset tydeligere (dvs.: bygge en shell-rørledning dynamisk)

Svar

git grep

Her er syntaksen ved hjelp av git grep kombinere flere mønstre ved hjelp av boolske uttrykk:

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

Kommandoen ovenfor vil skrive ut linjer som samsvarer med alle mønstrene samtidig.

--no-index Søk i filer i den aktuelle katalogen som ikke administreres av Git.

Merk av man git-grep for hjelp.

Se også:

For ELLER operasjon, se:

Kommentarer

  • Suveren svar. Tusen takk.

Svar

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

Bruk find . -type f etterfulgt av like mange
-exec grep -q "first_word" {} \;
og det siste nøkkelordet med
-exec grep -l "nth_word" {} \;

-q stille / stille
-l vis filer med treff

Følgende returnerer liste over filnavn med ordene «kanin» og «hull» i seg:
find . -type f -exec grep -q "rabbit" {} \; -exec grep -l "hole" {} \;

Kommentarer

  • Hvis du ser nøye, kan du bare lære at dette ikke er funksjonaliteten som spørsmålet ber om.

Svar

ripgrep

Her er eksemplet som bruker rg :

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

Det er et av de raskeste grepping-verktøyene, siden det er bygget på toppen av Rusts regex-motor som bruker endelige automata, SIMD og aggressive bokstavelige optimaliseringer for å gjøre søket veldig raskt.

Se også relaterte funksjonsforespørsel på div id = «ee5a593f1e»>

GH-875 .

Svar

For å finne alle ordene (eller mønstrene), kan du kjøre grep i en for -sløyfe. Den største fordelen her er å søke fra en liste over regulære uttrykk .

Et reelt 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 

La oss nå kjøre den på denne filen:

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

  • Logikken din er feil – jeg ba om ALL operatør, koden din fungerer som OR operator, ikke AND. Og btw. For det (OR) er mye enklere løsning gitt rett i spørsmålet.
  • @greenoldman Logikken er enkel: For vil løkke på ALLE ord / mønstre i listen, og hvis den finnes i filen – vil skrive den ut. Så bare fjern den andre hvis du ikke ‘ ikke trenger handling hvis ord ikke ble funnet.
  • Jeg forstår logikken din så vel som spørsmålet mitt – jeg spurte om AND operatør, noe som betyr at filen bare er en positiv hit hvis den samsvarer med mønster A og mønster B og mønster C og … AND I ditt tilfelle er filen en positiv hit hvis den ma tches mønster A eller mønster B eller … Ser du forskjellen nå?
  • @greenoldman usikker på hvorfor du tror at denne sløyfen ikke kontrollerer OG tilstand for alle mønstre? Så jeg ‘ har redigert svaret mitt med et reelt eksempel: Det vil søke i fil etter alle regexer i listen, og på den første som mangler – vil avslutte med feil.
  • Du har det rett foran øynene dine, du har positiv kamp like etter at første kamp er utført. Du bør ha » samle » alle utfall og beregne AND på dem. Deretter bør du omskrive skriptet for å kjøre på flere filer – så kanskje du skjønner at spørsmålet allerede er besvart, og forsøket ditt ikke gir noe til bordet, beklager.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *