Jag skulle vilja få matchningen med flera mönster med implicit OCH mellan mönster, dvs. motsvarar att köra flera greps i en sekvens:
grep pattern1 | grep pattern2 | ...
Så hur konverterar man det till något liknande?
grep pattern1 & pattern2 & pattern3
Jag skulle vilja använda enstaka grep eftersom jag bygger argument dynamiskt, så allt måste passa i en sträng. Att använda filter är systemfunktion, inte grep, så det är inget argument för det.
Förväxla inte den här frågan med:
grep "pattern1\|pattern2\|..."
Detta är en ELLER matchning med flera mönster.
Kommentarer
Svar
agrep
kan göra det med den här syntaxen:
agrep "pattern1;pattern2"
Med GNU grep
, när den byggs w med PCRE-stöd kan du göra:
grep -P "^(?=.*pattern1)(?=.*pattern2)"
Med ast grep
:
grep -X ".*pattern1.*&.*pattern2.*"
(lägger till .*
s som <x>&<y>
matchar strängar som matchar både <x>
och <y>
exakt , a&b
skulle aldrig matcha eftersom det inte finns någon sådan sträng som kan vara både a
och b
samtidigt).
Om mönstren inte överlappar varandra kan du också göra:
grep -e "pattern1.*pattern2" -e "pattern2.*pattern1"
Det bästa bärbara sättet är förmodligen med awk
som redan nämnts:
awk "/pattern1/ && /pattern2/"
Med sed
:
sed -e "/pattern1/!d" -e "/pattern2/!d"
Var uppmärksam på att alla dessa har olika syntax för reguljära uttryck.
Kommentarer
-
agrep
syntax fungerar inte för mig … vilken version introducerades den i? - @Raman 2.04 från 1992 hade den redan. Jag ’ har ingen anledning att tro att det inte fanns ’ från början. Nyare (efter 1992) versioner av
agrep
finns med glimt / webglimpse . Möjligen har du en annan implementering. Jag hade dock ett misstag för ast-grep-versionen, men alternativet för augmented regexps är-X
, inte-A
. - @St é phaneChazelas Tack, jag har
agrep
0.8.0 på Fedora 23. Detta verkar vara en annanagrep
än den du refererar till. - @Raman, din låter som TRE
agrep
. - @Techiee, eller bara
awk '/p1/ && /p2/ {n++}; END {print 0+n}'
Svar
Du specificerade inte grep-versionen, det här är viktigt. Vissa regexp-motorer tillåter flera matchningar med OCH med ”& ”men det här är icke-standard och icke-bärbar funktion. Men åtminstone GNU grep stöder inte detta.
OTOH du kan helt enkelt ersätta grep med sed, awk, perl, etc . (listad i viktordning). Med awk skulle kommandot se ut som
awk "/regexp1/ && /regexp2/ && /regexp3/ { print; }"
och det kan konstrueras för att specificeras på kommandoraden på ett enkelt sätt.
Kommentarer
- Kom bara ihåg att
awk
använder ERE ’ s, t.ex. motsvarandegrep -E
, i motsats till BRE ’ som vanliggrep
använder. -
awk
’ s regexer kallas ERE, men faktiskt ’ är lite idiosynkratiskt. Här är förmodligen mer detaljer än någon bryr sig om: wiki.alpinelinux.org/wiki/Regex - Tack, grep 2.7.3 ( openSUSE). Jag röstade upp dig, men jag kommer att hålla frågan öppen ett tag, kanske finns det något knep för grep (inte att jag ogillar
awk
– att bara veta mer är bättre). - Standardåtgärden är att skriva ut den matchande raden så att
{ print; }
-delen inte är ’ inte verkligen nödvändig eller användbar här.
Svar
Om patterns
innehåller ett mönster per rad, du kan göra något så här:
awk "NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1" patterns -
Eller så matchar det strängar istället för vanliga uttryck:
awk "NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1" patterns -
För att skriva ut allt istället för inga rader i ingången om patterns
är tom, ersätt NR==FNR
med FILENAME==ARGV[1]
, eller med ARGIND==1
i gawk
.
Dessa funktioner skriver ut raderna i STDIN som innehåller varje sträng som anges som ett argument som en understräng. ga
står för grep all och gai
ignorerar fall.
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 adresserar flera användningsfall och fungerar (verifierat på macos)
Svar
grep pattern1 | grep pattern2 | ...
Jag skulle vilja använda enstaka grep eftersom jag bygger argument dynamiskt , så allt måste passa i en sträng
Det är faktiskt möjligt att bygga rörledningen dynamiskt (utan att ta till 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 är troligen inte en särskilt effektiv lösning.
Kommentarer
- Använd antingen
chained-grep()
ellerfunction chained-grep
men intefunction chained-grep()
: unix.stackexchange.com/questions/73750/… - Kan du beskriva vad tricket är? Kan du lägga till det i svaret ( utan ” Redigera: ”, ” Uppdatering: ” eller liknande) genom att redigera den ?
- Omformulerade svaret för att göra tricket tydligare (dvs. bygga en skalrörledning dynamiskt)
Svar
git grep
Här är syntaxen med git grep
kombinerar flera mönster med booleska uttryck:
git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3
Kommandot ovan skriver ut rader som matchar alla mönster samtidigt.
--no-index
Sök efter filer i den aktuella katalogen som inte hanteras av Git.
Kontrollera man git-grep
för hjälp.
Se även:
- Hur man gör e grep för att matcha sträng1 OCH sträng2?
- Kontrollera om alla flera strängar eller regex finns i en fil .
För operation ELLER , se:
- Hur grep jag för flera mönster med mönster med rörkaraktär?
- Grep: hur lägger man till en ” ELLER ” villkor?
Kommentarer
- Fantastiskt svar. Tack.
Svar
Här är min uppfattning, och detta fungerar för ord i flera rader:
Använd find . -type f
följt av lika många
-exec grep -q "first_word" {} \;
och det sista nyckelordet med
-exec grep -l "nth_word" {} \;
-q
tyst / tyst
-l
visa filer med matchningar
Följande returnerar en lista med filnamn med orden ”kanin” och ”hål” i dem:
find . -type f -exec grep -q "rabbit" {} \; -exec grep -l "hole" {} \;
Kommentarer
- Om du tittar noga kan du bara lära dig att detta inte är den funktion som frågan frågar efter.
Svar
ripgrep
Här är exemplet med rg
:
rg -N "(?P<p1>.*pattern1.*)(?P<p2>.*pattern2.*)(?P<p3>.*pattern3.*)" file.txt
Det är ett av de snabbaste greppverktygen, eftersom det är byggt ovanpå Rusts regex-motor som använder ändliga automata, SIMD och aggressiva bokstavsoptimeringar för att göra sökningen mycket snabb.
Se även relaterad funktionsbegäran på GH-875 .
Svar
För att hitta alla orden (eller mönstren) kan du köra grep
i en for
-slinga. Den största fördelen här är att söka från en -lista med reguljära uttryck .
Ett riktigt exempel:
# 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
Låt oss nu köra den på den här 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
- Din logik är felaktig – jag bad om
ALL
operatör, din kod fungerar somOR
operatör, inteAND
. Och btw för det (OR
) är mycket enklare lösning ges rätt i frågan. - @greenoldman Logiken är enkel: For kommer att slinga på ALLA ord / mönster i listan, och om den finns i filen – kommer att skriva ut den. Så ta bara bort den andra om du inte ’ inte behöver åtgärda om ord inte hittades.
- Jag förstår din logik såväl som min fråga – jag frågade om
AND
operatör, vilket betyder att filen bara är en positiv träff om den matchar mönster A och mönster B och mönster C och …AND
I ditt fall är filen en positiv träff om den ma tches mönster A eller mönster B eller … Ser du skillnaden nu? - @greenoldman inte säker på varför du tror att den här slingan inte kontrollerar OCH villkor för alla mönster? Så jag ’ har redigerat mitt svar med ett verkligt exempel: Det kommer att söka i filen för alla regex i listan, och på den första som saknas – kommer att avslutas med fel.
- Du har det framför ögonen, du har en positiv matchning precis efter att den första matchen har genomförts. Du bör ha ” samla ” alla resultat och beräkna
AND
på dem. Då borde du skriva om manuset för att köras på flera filer – då kanske du inser att frågan redan har besvarats och ditt försök inte ger något till bordet, tyvärr.
foo
och rader som innehållerbar
” se med grep för flera sökmönster