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 annenagrep
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. tilsvarergrep -E
, i motsetning til BRE ‘ s som vanliggrep
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 "$@") -; } 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 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 "$@" } 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()
ellerfunction chained-grep
men ikkefunction 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å:
- Hvordan du e grep for å matche streng1 OG streng2?
- Sjekk om alle flere strenger eller regexer finnes i en fil .
For ELLER operasjon, se:
- Hvordan tar jeg tak i flere mønstre med mønster som har et rørkarakter?
- Grep: hvordan legger du til en » ELLER » tilstand?
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 somOR
operator, ikkeAND
. 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.
foo
og linjer som inneholderbar
» se ved hjelp av grep for flere søkemønstre