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 annan agrep ä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. motsvarande grep -E, i motsats till BRE ’ som vanlig grep 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() eller function chained-grep men inte function 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:

För operation ELLER , se:

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 som OR operatör, inte AND. 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.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *