Chtěl bych získat shodu více vzorů s implicitní AND mezi vzory, tj. ekvivalentní běhu několika grepsů v sekvenci:

grep pattern1 | grep pattern2 | ... 

Jak to tedy převést na něco podobného?

grep pattern1 & pattern2 & pattern3 

Chtěl bych použít jeden grep, protože vytvářím argumenty dynamicky, takže vše musí zapadat do jednoho řetězce. Použití filtru je systémová funkce, nikoli grep, takže to není argument.


Nezaměňujte tuto otázku s:

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

Toto je NEBO shoda více vzorů.

Komentáře

odpověď

agrep to dokáže pomocí této syntaxe:

agrep "pattern1;pattern2" 

S GNU grep, když je postaveno w S podporou PCRE můžete:

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

S ast grep :

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

(přidání .* s jako <x>&<y> odpovídá řetězcům, které odpovídají <x> i <y> přesně , by se nikdy neshodovalo, protože neexistuje žádný takový řetězec, který by mohl být a i b současně).

Pokud se vzory nepřekrývají, můžete také:

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

Nejlepší přenosný způsob je pravděpodobně s awk, jak již bylo zmíněno:

awk "/pattern1/ && /pattern2/" 

S sed:

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

Upozorňujeme, že všechny budou mít odlišnou syntaxi regulárního výrazu.

Komentáře

  • Syntaxe agrep nefunguje pro já … ve které verzi byla zavedena?
  • @Raman 2.04 z roku 1992 ji již měl. ‚ Nemám důvod se domnívat, že to od začátku nebylo ‚. Novější (po roce 1992) verze agrep lze najít v glimpse / webglimpse . Možná máte jinou implementaci. Měl jsem však chybu ve verzi ast-grep, možnost rozšířených regexps je -X, ne -A.
  • @St é phaneChazelas Díky, ve Fedoře 23. mám agrep 0.8.0. Zdá se, že být jiný agrep než ten, na který odkazujete.
  • @Raman, váš zvuk zní jako TRE agrep .
  • @Techiee, nebo jen awk '/p1/ && /p2/ {n++}; END {print 0+n}'

Odpověď

Neuvedli jste grep verzi, to je důležité. Některé motory regexp umožňují více shody seskupené pomocí AND pomocí „& „ale toto je nestandardní a nepřenosná funkce. Ale alespoň GNU grep to nepodporuje.

OTOH můžete jednoduše nahradit grep sedem, awk, perl atd. (uvedeny v pořadí podle zvýšení hmotnosti). S awk by příkaz vypadal jako

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

a lze jej zkonstruovat tak, aby jej bylo možné snadno zadat v příkazovém řádku.

Komentáře

  • Nezapomeňte, že awk používá ERE ‚ s, např. ekvivalent grep -E na rozdíl od BRE ‚ s, které používá grep.
  • awk ‚ s regulární výrazy se nazývají ERE, ale ve skutečnosti ‚ znovu trochu výstřední. Tady je pravděpodobně více podrobností, než o které se někdo stará: wiki.alpinelinux.org/wiki/Regex
  • Děkuji, grep 2.7.3 ( openSUSE). Hlasoval jsem pro vás, ale na chvíli nechám otázku otevřenou, možná existuje nějaký trik pro grep (ne že bych neměl rád awk – prostě vědět víc je lepší).
  • Výchozí akcí je vytisknout odpovídající řádek, takže část { print; } zde není ‚ opravdu nutná ani užitečná.

Odpověď

Pokud patterns obsahuje jeden vzor na řádek, můžete udělat něco takového:

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

Nebo se to shoduje s podřetězci místo běžných výrazy:

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

Chcete-li vytisknout všechny namísto řádků vstupu v v případě, že je patterns prázdný, nahraďte NR==FNR řetězcem FILENAME==ARGV[1] nebo ARGIND==1 v gawk.

Tyto funkce tisknou řádky STDIN, které obsahují každý řetězec zadaný jako argument jako podřetězec. ga znamená grep all a gai ignoruje velká a malá písmena.

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

Komentáře

  • ostrá odpověď, která řeší několik případů použití a funguje (ověřeno na MacOS)

Odpověď

grep pattern1 | grep pattern2 | ...

Chtěl bych použít jeden grep, protože stavím argumenty dynamicky , takže vše musí zapadat do jednoho řetězce

Ve skutečnosti je možné plynovod budovat dynamicky (bez použití 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  

Pravděpodobně to však není příliš efektivní řešení.

Komentáře

  • Použijte buď chained-grep() nebo function chained-grep, ale ne function chained-grep(): unix.stackexchange.com/questions/73750/…
  • Můžete popsat, o jaký trik jde? Můžete jej přidat k odpovědi ( bez “ Upravit: „, “ Aktualizace: “ apod.) provedením úpravou ?
  • Reformuloval odpověď, aby byl trik jasnější (tj .: dynamicky budujte plynovod shellu)

Odpověď

git grep

Zde je syntaxe používající git grep kombinující více vzorů pomocí booleovských výrazů:

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

Výše uvedený příkaz vytiskne řádky odpovídající všem vzorům najednou.

--no-index Hledání souborů v aktuálním adresáři, který není spravován Gitem.

Zaškrtněte man git-grep o pomoc.

Viz také:

O operaci OR viz:

Komentáře

  • Skvělá odpověď. Děkuji.

Odpověď

Tady je můj výběr, který funguje pro slova ve více řádcích:

Použijte find . -type f následované tolika
-exec grep -q "first_word" {} \;
a posledním klíčovým slovem s
-exec grep -l "nth_word" {} \;

-q tichý / tichý
-l zobrazit soubory se shodami

Následující seznam vrátí názvy souborů se slovy „králík“ a „díra“:
find . -type f -exec grep -q "rabbit" {} \; -exec grep -l "hole" {} \;

Komentáře

  • Pokud se podíváte pozorně, možná zjistíte, že nejde o funkčnost, kterou otázka požaduje.

Odpověď

ripgrep

Zde je příklad použití rg :

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

Je to jeden z nejrychlejších grepových nástrojů, protože je postaven nad Rustův regex engine , který využívá konečné automaty, SIMD a agresivní doslovné optimalizace, aby hledání bylo velmi rychlé.

Viz také požadavek související funkce na GH-875 .

Odpověď

Chcete-li najít všechna slova (nebo vzory), můžete spustit grep ve smyčce for. Hlavní výhodou zde je vyhledávání ze seznamu regulárních výrazů .

Skutečný příklad:

# 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 

Nyní to spustíme v tomto souboru:

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! 

Komentáře

  • Vaše logika je vadná – požádal jsem o ALL operátor, váš kód funguje jako OR operátor, ne AND. A btw. Za to (OR) je mnohem jednodušší řešení dané přímo v otázce.
  • @greenoldman Logika je jednoduchá: smyčka for bude smyčka na VŠECHNA slova / vzory v seznamu, a pokud je nalezen v souboru – vytiskne jej. Pokud tedy ‚ nepotřebujete akci v případě, že slovo nebylo nalezeno, jednoduše odstraňte else.
  • Rozumím vaší logice i mé otázce – ptal jsem se na operátor AND, což znamená, že soubor je pouze pozitivním zásahem, pokud odpovídá vzoru A a vzoru B a vzor C a … AND Soubor je ve vašem případě kladný zásah, pokud má tches vzor A nebo vzor B nebo … Vidíte nyní rozdíl?
  • @greenoldman nejste si jisti, proč si myslíte, že tato smyčka nekontroluje podmínku AND pro všechny vzory? Takže jsem ‚ upravil svou odpověď skutečným příkladem: Prohledá v souboru všechny regexe seznamu a na prvním, který chybí – ukončí s chybou.
  • Máte to přímo před očima, máte pozitivní shodu hned po provedení prvního zápasu. Měli byste “ shromáždit “ všechny výsledky a spočítat AND na nich. Pak byste měli přepsat skript, který se má spustit na více souborech – pak si možná uvědomíte, že otázka je již zodpovězena a váš pokus nepřinese nic na stůl, promiňte.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *