Tato otázka již má odpovědi zde :

Komentáře

  • Co tím myslíte autor " celou část každého řetězce "? Nechcete ' vytisknout celý řádek?
  • Můžete potvrdit, že chcete, aby odpovídající soubory obsahovaly " foo " a " 321 ", ale nejen " foo " nebo jen " 321 "?
  • Líbí se mi, jak ' s 321 místo bar: – D

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ěmi exec 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že grep -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 a grep -l nehledá na konec souboru: ukončí se ihned protože je nalezena shoda. Zajímá mě, proč první řešení není ' t for 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 * Ale for 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)

Napsat komentář

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