Ik zou graag de multi-patroonovereenkomst willen krijgen met impliciet EN tussen patronen, dwz gelijk aan het uitvoeren van meerdere greps in een reeks:

grep pattern1 | grep pattern2 | ... 

Dus hoe converteer je het naar zoiets?

grep pattern1 & pattern2 & pattern3 

Ik zou enkele grep willen gebruiken omdat ik dynamisch argumenten aan het opbouwen ben, dus alles moet in één string passen. Het gebruik van een filter is een systeemfunctie, geen grep, dus het is er geen argument voor.


Verwar deze vraag niet met:

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

Dit is een OF overeenkomst met meerdere patronen.

Reacties

Antwoord

agrep kan het doen met deze syntaxis:

agrep "pattern1;pattern2" 

Met GNU grep, wanneer gebouwd w et PCRE-ondersteuning kunt u het volgende doen:

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

Met ast grep :

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

(.* s toevoegen als <x>&<y> komt overeen met strings die overeenkomen met zowel <x> als <y> exact , a&b zou nooit overeenkomen omdat er” geen string is die zowel a als b tegelijkertijd).

Als de patronen elkaar niet “overlappen, kunt u mogelijk ook doen:

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

De beste draagbare manier is waarschijnlijk met awk zoals reeds vermeld:

awk "/pattern1/ && /pattern2/" 

Met sed:

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

Houd er rekening mee dat al deze een verschillende reguliere expressiesyntaxis hebben.

Opmerkingen

  • De agrep syntaxis werkt niet voor me … in welke versie is het geïntroduceerd?
  • @Raman 2.04 uit 1992 had het al. Ik ‘ heb geen reden om aan te nemen dat het er vanaf het begin niet ‘ was. Nieuwere (na 1992) versies van agrep kunnen worden gevonden in glimpse / webglimpse . Mogelijk heeft u een andere uitvoering. Ik had echter een fout met de ast-grep-versie, de optie voor augmented regexps is -X, niet -A.
  • @St é phaneChazelas Bedankt, ik heb agrep 0.8.0 op Fedora 23. Dit lijkt op een andere agrep zijn dan degene waarnaar u verwijst.
  • @Raman, de uwe klinkt als TRE agrep .
  • @Techiee, of gewoon awk '/p1/ && /p2/ {n++}; END {print 0+n}'

Antwoord

U heeft “geen grep-versie gespecificeerd, dit is belangrijk. Sommige regexp-engines staan meerdere matching-groepen toe door EN met” & “maar dit is een niet-standaard en niet-draagbare functie. Maar GNU grep ondersteunt dit tenminste niet.

OTOH je kunt grep eenvoudig vervangen door sed, awk, perl, enz. . (weergegeven in volgorde van gewichtstoename). Met awk ziet het commando eruit als

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

en het kan zo worden geconstrueerd dat het op een gemakkelijke manier in de commandoregel gespecificeerd kan worden.

Opmerkingen

  • Onthoud dat awk ERE ‘ s gebruikt, bijv. het equivalent van grep -E, in tegenstelling tot de BRE ‘ s die gewoon grep gebruikt.
  • awk ‘ s regexes worden genoemd EREs, maar in feite zijn ze ‘ zijn een beetje idiosyncratisch. Hier zijn waarschijnlijk meer details dan waar iemand om geeft: wiki.alpinelinux.org/wiki/Regex
  • Bedankt, grep 2.7.3 ( openSUSE). Ik heb je gestemd, maar ik zal de vraag een tijdje open houden, misschien is er een truc voor grep (niet dat ik een hekel heb aan awk – gewoon meer weten is beter).
  • De standaardactie is om de overeenkomende regel af te drukken, zodat het { print; } deel niet ‘ hier echt nodig of nuttig is.

Antwoord

Als patterns één patroon per regel bevat, je kunt zoiets als dit doen:

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

Of dit komt overeen met subtekenreeksen in plaats van gewone expressies:

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

Om alles af te drukken in plaats van geen regels van de invoer in de het geval dat patterns leeg is, vervang dan NR==FNR door FILENAME==ARGV[1], of door ARGIND==1 in gawk.

Deze functies drukken de regels van STDIN af die elke string bevatten die is gespecificeerd als een argument als een subtekenreeks. ga staat voor grep all en gai negeert hoofdletters / kleine letters.

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

Reacties

  • helder antwoord dat verschillende gebruikssituaties behandelt en werkt (geverifieerd op macOS)

Antwoord

grep pattern1 | grep pattern2 | ...

Ik zou single grep willen gebruiken omdat ik argumenten dynamisch bouw, dus alles moet in één string passen

Het is eigenlijk mogelijk om de pijplijn dynamisch op te bouwen (zonder toevlucht te nemen tot 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  

Het is waarschijnlijk echter geen erg efficiënte oplossing.

Opmerkingen

  • Gebruik ofwel chained-grep() of function chained-grep maar niet function chained-grep(): unix.stackexchange.com/questions/73750/…
  • Kun je beschrijven wat de truc is? Kun je het toevoegen aan het antwoord ( zonder ” Bewerken: “, ” Update: “, of vergelijkbaar) door te bewerken ?
  • Het antwoord opnieuw geformuleerd om de truc duidelijker te maken (dwz: dynamisch een shell-pijplijn bouwen)

Antwoord

git grep

Hier is de syntaxis met git grep door meerdere patronen te combineren met Booleaanse expressies:

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

Het bovenstaande commando zal regels afdrukken die overeenkomen met alle patronen in één keer.

--no-index Zoek bestanden in de huidige directory die niet worden beheerd door Git.

Controleer man git-grep voor hulp.

Zie ook:

Voor OF bewerking, zie:

Reacties

  • Uitstekend antwoord. Dank je.

Antwoord

Hier is mijn mening, en dit werkt voor woorden in meerdere regels:

Gebruik find . -type f gevolgd door evenveel
-exec grep -q "first_word" {} \;
en het laatste trefwoord met
-exec grep -l "nth_word" {} \;

-q stil / stil
-l bestanden weergeven met overeenkomsten

De volgende retourneert een lijst met bestandsnamen met de woorden “konijn” en “gat” erin:
find . -type f -exec grep -q "rabbit" {} \; -exec grep -l "hole" {} \;

Opmerkingen

  • Als je goed kijkt, kom je er misschien achter dat dit niet de functionaliteit is waar de vraag om vraagt.

Antwoord

ripgrep

Hier is het voorbeeld met rg :

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

Het is een van de snelste grijpgereedschappen, aangezien het is gebouwd bovenop Rusts regex-engine die gebruikmaakt van eindige automaten, SIMD en agressieve letterlijke optimalisaties om het zoeken erg snel te maken.

Zie ook gerelateerd functieverzoek op GH-875 .

Antwoord

Om alle woorden (of patronen) te vinden, kun je grep in een for lus uitvoeren. Het belangrijkste voordeel hier is het zoeken vanuit een lijst met reguliere expressies .

Een echt voorbeeld:

# 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 

Laten we het nu op dit bestand uitvoeren:

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! 

Reacties

  • Je logica is defect – ik vroeg om ALL operator, je code werkt als OR operator, niet als AND. En trouwens. Voor dat (OR) is een veel eenvoudigere oplossing die direct in de vraag wordt gegeven.
  • @greenoldman De logica is simpel: de for zal doorlopen op ALLE woorden / patronen in de lijst, en als het wordt gevonden in het bestand – zal het afdrukken. Dus verwijder gewoon de else als je geen ‘ actie nodig hebt voor het geval het woord niet werd gevonden.
  • Ik begrijp zowel uw logica als mijn vraag – ik vroeg naar de AND operator, wat betekent dat het bestand alleen een positieve treffer is als het overeenkomt met patroon A en patroon B en patroon C en … AND In het geval dat het bestand positief is geraakt als het ma tches patroon A of patroon B of … Zie je het verschil nu?
  • @greenoldman weet je niet zeker waarom je denkt dat deze lus de AND-conditie niet voor alle patronen controleert? Dus ik ‘ heb mijn antwoord bewerkt met een echt voorbeeld: het zal in het bestand zoeken naar alle regex van de lijst, en op de eerste die ontbreekt, zal het afsluiten met een foutmelding.
  • Je hebt het recht voor je ogen, je hebt een positieve match net nadat de eerste match is uitgevoerd. U moet ” verzamelen ” alle resultaten hebben en er AND op berekenen. Dan zou je het script moeten herschrijven zodat het op meerdere bestanden kan draaien – dan realiseer je je misschien dat de vraag al beantwoord is en dat je poging niets oplevert, sorry.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *