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ř. ekvivalentgrep -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()
nebofunction chained-grep
, ale nefunction 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é:
- Jak k nám e grep, aby odpovídal řetězci1 A řetězci2?
- Zkontrolujte, zda v souboru existuje více řetězců nebo regulárních výrazů .
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 jakoOR
operátor, neAND
. 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.
foo
a řádky, které obsahujíbar
“ viz použití grepu pro více vyhledávacích vzorů