Komentáře
Odpověď
GNU grep
Mělo by to být trochu rychlejší, protože druhá grep
může pracovat se seznamem souborů.
grep -lZ "foo" * | xargs -0 grep -l "321"
POSIX grep s find
find
je užitečnější, pokud chcete prohledávat rekurzivní adresáře (v takovém případě ztratíte -mindepth
a -maxdepth
možnosti.
find . -mindepth 1 -maxdepth 1 -type f -exec grep -q "foo" {} \; -exec grep -l "321" {} +
Komentáře
-
-r
fungoval dobře na prvnígrep
, aby toto GNU řešení pro mě bylo rekurzivní, místo použití řádku POSIX se všemi těmiexec
s
odpověď
Můžete to udělat pomocí krátkého skriptu:
for FILE in * do grep -q foo $FILE && grep -q 321 $FILE && echo $FILE done
Můžete to udělat také na jednom řádku:
for FILE in *; do grep -q foo $FILE && grep -q 321 $FILE && echo $FILE; done
grep
vrací 0 (true), pokud našel řetězec a &&
oddělující příkazy znamená, že druhý bude fungovat pouze v případě, že první byl pravdivý. Možnost -q
zajišťuje, že grep
nic nevydá.
Echo se spustí, pouze pokud byly oba řetězce našel ve stejném souboru.
Myslel jsem na jiný způsob, jak to udělat. Tento způsob bude pravděpodobně efektivnější, pokud jsou příslušné soubory větší než nainstalovaná paměť RAM, protože musí grep
procházet každým souborem pouze jednou.
for FILE in * do test $(egrep -o "foo|321" $FILE | uniq | sort | uniq | wc -l) -eq 2 && echo $FILE done
a jednorázová verze:
for FILE in *; do test $(egrep -o "foo|321" $FILE | uniq | sort | uniq | wc -l) -eq 2 && echo $FILE; done
Komentáře
- Pro vaše efektivnější řešení: co když má soubor " foo foo "?
- To ' k čemu
uniq | sort | uniq
slouží. " foo foo " končí jako jeden řádek, ale " foo 321 " končí jako dva řádky, protožegrep -o
vypíše všechny nalezené řetězce na samostatných řádcích, i když začaly na stejném řádku. - Pokud se soubory stanou tak obrovskými, že by bylo v pořádku vidličkovat alespoň šestkrát na soubor, pak by pravděpodobně mělo smysl použít místo toho awk, takže soubory nemusí být prohledávány až do konce.
- @Ladadadada to. 🙂
- @HaukeLaging
grep -q
agrep -l
nehledá na konec souboru: ukončí se ihned protože je nalezena shoda. Zajímá mě, proč první řešení není ' tfor FILE in *; do grep -q foo "$FILE" && grep -l 321 "$FILE"; done
odpověď
Zvláštní. Pro mě fungují obě varianty (grep (GNU grep) 2.13):
grep "foo\|321" grep -E "foo|321"
Upravit 1 – zobrazit soubory pouze s oběma shodami
Odpověď for file in *
funguje, ale může se stát noční můrou výkonu (pro velké množství souborů) ): alespoň dva procesy na soubor. To je rychlejší (ve světě GNU):
find . -type f -print0 | xargs -0 -r grep --files-with-matches --null -- string1 | xargs -0 -r grep --files-with-matches -- string2
řetězec1 by měl být ten, který má za následek méně shod.
Komentáře
- Tazatel hledá výsledek, který má vrátit hodnotu true, pouze pokud soubor obsahuje oba řetězce, spíše než pokud odpovídá alespoň jednomu.
- Líbí se mi to
--files-with-matches
možnost. Prostě si to přečtěte na manuálové stránce a způsobí to, že se grep zastaví, jakmile najde první shodu, což znamená, že je ' velmi efektivní pro velké soubory, pokud ke shodě dojde dříve. Rovněž říká, že krátká volba-l
je specifikována POSIXem, takže ji lze použít i mimo svět GNU. - @Ladadadada Účinnost není výhodou oproti vašemu -q, ačkoli. Když jsem zmínil GNU, nemyslel jsem ' na –files-with-match, ale na -0 / –null.Co mě právě napadne: Rozšíření cesty obsahuje abecední řazení (opravdu špatné: Zdá se, že ' nelze ani vypnout), takže pro obrovské množství souborů i vaše
for file in *
opravdu přestává být zábavná. - Optimalizace účinnosti by ve skutečnosti byla u několika velkých souborů zcela odlišná od mnoha malých a
*
prostě ' po několika tisících souborů vůbec nebude fungovat. - @Ladadadada To by ' t funguje jako součást příkazového řádku pro externí příkaz:
grep foo *
Alefor file in *
je struktura vnitřního prostředí, takže bych předpokládal že zde není použitelný limit příkazového řádku.
Odpovědět
V zásadě najít všechny soubory včetně konkrétního řetězec v adresáři, můžete použít:
grep -lir "pattern" /path/to/the/dir
-
-l
: k provedení tohoto skenování zastaví se při první shodě -
-i
: ignorovat rozlišování malých a velkých písmen ve vzorech i ve vstupních souborech -
-r
: rekurzivně prohledávat všechny soubory v adresáři
Chcete-li hledat dva vzory, zkuste toto:
grep -lr "321" $(grep -lr "foo" /path/to/the/dir)
Komentáře
- Platí standardní nudné komentáře o tom, že
$()
dobře nezpracovává mezery. V praxi pro jeden liner v shellu bude tento příkaz fungovat dobře.
Odpověď
Mělo by být
grep -e "foo" -e "321" *
Použijte -e pro více vzorů
EDIT
V případě, že potřebujete shodu obou:
grep -e ".*foo.*321.*" *
Pokud na pořadí nezáleží:
grep -e ".*foo.*321.*" ".*321.*foo.*" *
Komentáře
- Toto neposkytuje odpověď na otázku. Chcete-li od autora kritizovat nebo požádat o vysvětlení, zanechte komentář pod jeho příspěvkem.
- @mdpc Myslím, že poskytuje odpověď. Co vás odlišuje od ostatních?
- @HaukeLaging Protože se vrátí, pokud se shoduje některý ze vzorů. OP hledá případ, kdy vrátí pouze true, pokud jsou v souboru nalezeny oba .
- Podle mého chápání to najde pouze soubory, kde oba řetězce obsahují na stejném řádku (I ' nemyslíte. ve výchozím nastavení odpovídá novým řádkům)
321
místobar
: – D