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 andereagrep
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 vangrep -E
, in tegenstelling tot de BRE ‘ s die gewoongrep
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()
offunction chained-grep
maar nietfunction 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:
- Hoe bij ons e grep om string1 EN string2 te matchen?
- Controleer of alle meerdere strings of regexes in een bestand voorkomen .
Voor OF bewerking, zie:
- Hoe kan ik grijpen voor meerdere patronen met een patroon met een pipe-teken?
- Grep: hoe voeg je een ” OF toe ” conditie?
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 alsOR
operator, niet alsAND
. 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.
foo
bevatten en regels diebar
” zie grep gebruiken voor meerdere zoekpatronen