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 andenagrep
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 tilgrep -E
i modsætning til BRE ‘ s, som almindeliggrep
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()
ellerfunction chained-grep
men ikkefunction 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å:
- Sådan gør vi e grep for at matche streng1 OG streng2?
- Kontroller, om alle flere strenge eller regexer findes i en fil .
For ELLER operation, se:
- Hvordan griber jeg om flere mønstre med mønster med en rørkarakter?
- Grep: hvordan tilføjes en ” ELLER ” betingelse?
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 somOR
operator, ikkeAND
. 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.
foo
og linjer, der indeholderbar
” se ved hjælp af grep til flere søgemønstre