Co je účinnější pro zjištění, které soubory v celém souborovém systému obsahují řetězec: rekurzivní grep nebo najít s grep v příkazu exec? Předpokládám, že najít by bylo efektivnější, protože můžete alespoň provést nějaké filtrování, pokud znáte příponu souboru nebo regex, který odpovídá názvu souboru, ale když víte pouze -type f
což je lepší ? GNU grep 2.6.3; najít (GNU findutils) 4.4.2
Příklad:
grep -r -i "the brown dog" /
find / -type f -exec grep -i "the brown dog" {} \;
Komentáře
Odpověď
Nejsem si jistý:
grep -r -i "the brown dog" /*
je to, co jste opravdu mysleli. To by znamenalo rekurzivně grep všechny neskryté soubory a adresáře v /
(ale stále se dívejte do skrytých souborů a adresářů v nich).
Za předpokladu, že jste mysleli:
grep -r -i "the brown dog" /
Několik poznámek:
- Ne všechny
grep
implementace podporují-r
. A mezi těmi, které se liší, se chování liší: někteří při procházení adresářovým stromem sledují symbolické odkazy na adresáře (což znamená, že můžete vypadat jako verální časy ve stejném souboru nebo dokonce spuštěné v nekonečných smyčkách), některé nebudou. Některé nahlédnou do souborů zařízení (a bude to nějakou dobu trvat například v/dev/zero
) nebo do potrubí nebo binárních souborů …, jiné ne. - Je to efektivní, protože
grep
se začne dívat do souborů, jakmile je objeví. Ale když se podívá do souboru, už nehledá další soubory, ve kterých by mohl hledat (což je ve většině případů pravděpodobně stejně dobrý)
Vaše:
find / -type f -exec grep -i "the brown dog" {} \;
(odstranil -r
který zde nedal smysl) je strašně neefektivní, protože pro každý soubor spouštíte jeden grep
. ;
by měl být použit pouze pro příkazy, které přijímají pouze jeden argument. Navíc zde, protože grep
vypadá pouze v jednom souboru, nevytiskne název souboru, takže nevíte, kde jsou shody.
Vy “ nehledáte dovnitř soubory zařízení, kanály, symbolické odkazy …, nesledujete symbolické odkazy, ale stále se potenciálně díváte do věcí jako /proc/mem
.
find / -type f -exec grep -i "the brown dog" {} +
by bylo mnohem lepší, protože by bylo spuštěno co nejméně příkazů grep
. Název souboru získáte, pokud poslední běh nemá pouze jeden soubor. K tomu je lepší použít:
find / -type f -exec grep -i "the brown dog" /dev/null {} +
nebo GNU grep
:
find / -type f -exec grep -Hi "the brown dog" {} +
Upozorňujeme, že grep
nebude spuštěn, dokud find
našel dostatek souborů, aby je mohl žvýkat, takže dojde k počátečnímu zpoždění. A find
nebude pokračovat ve vyhledávání dalších souborů, dokud se nevrátí předchozí grep
. Přidělení a předání velkého seznamu souborů má určitý (pravděpodobně zanedbatelný) dopad, takže to bude pravděpodobně méně efektivní než grep -r
, který nebude následovat symbolický odkaz nebo hledat uvnitř zařízení.
S nástroji GNU:
find / -type f -print0 | xargs -r0 grep -Hi "the brown dog"
Jak je uvedeno výše, několik grep
instance se budou spouštět, ale find
bude pokračovat v hledání dalších souborů, zatímco první grep
vyvolání se bude dívat do první dávky. To však může, ale nemusí být výhoda.Například s daty uloženými na rotačních pevných discích zpomalí disk find
a grep
přístup k datům uloženým na různých místech na disku propustnost způsobením neustálého pohybu hlavy disku. V nastavení RAID (kde find
a grep
mohou přistupovat k různým diskům) nebo na discích SSD to může mít pozitivní rozdíl.
V nastavení RAID může také vylepšit spuštění několika souběžných grep
vyvolání. Přesto s nástroji GNU na úložišti RAID1 se 3 disky může
find / -type f -print0 | xargs -r0 -P2 grep -Hi "the brown dog"
výkon výrazně zvýšit. Nezapomeňte však, že druhý grep
bude spuštěn až poté, co bude nalezen dostatek souborů k vyplnění prvního grep
příkazu. K xargs
můžete přidat možnost -n
, aby k tomu došlo dříve (a předat méně souborů za grep
vyvolání).
Upozorňujeme, že pokud přesměrujete výstup xargs
na cokoli jiného než na koncové zařízení, pak greps
s začnou ukládat do vyrovnávací paměti svůj výstup, což znamená, že výstup těchto grep
s bude pravděpodobně nesprávně prokládán. Musíte použít stdbuf -oL
(je-li k dispozici, například na GNU nebo FreeBSD), aby to vyřešili (stále můžete mít problémy s velmi dlouhými řádky (obvykle> 4KiB)) nebo nechat každý napsat svůj výstup do samostatného souboru a všechny je zřetězit Nakonec.
Zde je řetězec, který hledáte, opravený (nikoli regexp), takže použití možnosti -F
může mít rozdíl (je nepravděpodobné, že grep
implementace už to umí optimalizovat).
Další věc, kterou cou Velký rozdíl spočívá v opravě národního prostředí na C, pokud používáte vícebajtové národní prostředí:
find / -type f -print0 | LC_ALL=C xargs -r0 -P2 grep -Hi "the brown dog"
Abyste se vyhnuli pohledu dovnitř /proc
, /sys
…, použijte -xdev
a určete souborové systémy, ve kterých chcete hledat:
LC_ALL=C find / /home -xdev -type f -exec grep -i "the brown dog" /dev/null {} +
Nebo ořezejte cesty, které chcete výslovně vyloučit:
LC_ALL=C find / \( -path /dev -o -path /proc -o -path /sys \) -prune -o \ -type f -exec grep -i "the brown dog" /dev/null {} +
Komentáře
- Nepředpokládám ‚, že by mě někdo mohl nasměrovat na zdroj – nebo vysvětlit – co {} a + znamenají. ‚ není nic, co bych mohl vidět na manuálových stránkách pro exec, grep nebo najít v poli Solaris i ‚ m použití. Je to jen shell zřetězení názvů souborů a jejich předání grepu?
- @Poldie, což je ‚ jasně vysvětleno v popisu
-exec
predikát na ruční stránce Solaris - Ah, ano. Při vyhledávání na stránce manuálu jsem ‚ neunikl ze svého {char. Váš odkaz je lepší; Zdá se mi hrozné číst manuálové stránky.
- RAID1 s 3 disky? Jak zvláštní …
- @tink, ano, RAID1 je na 2 nebo více discích. Se 3 disky ve srovnání se 2 disky zvýšíte redundanci a výkon čtení, zatímco výkon zápisu je zhruba stejný. U 3 disků na rozdíl od 2 to znamená, že můžete také opravit chyby, protože když se na jedné z kopií trochu převrátí, můžete ‚ zjistit, který je správný, zaškrtnutím všech 3 kopie, zatímco na 2 discích, můžete ‚ to opravdu říct.
Odpovědět
Pokud pro vás *
ve volání grep
není důležitý, první by měl být efektivnější, protože pouze jeden je spuštěna instance grep
a vidlice nejsou volné. Ve většině případů to bude rychlejší i s *
, ale v okrajových případech třídění by to mohlo zvrátit.
Mohou existovat i jiné find
– grep
struktury, které fungují lépe, zejména s mnoha malými Soubory. Čtení velkého množství položek souborů a inodů najednou může zlepšit výkon rotujících médií.
Ale pojďme se podívat na statistiky syscall:
najít
> strace -cf find . -type f -exec grep -i -r "the brown dog" {} \; % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 97.86 0.883000 3619 244 wait4 0.53 0.004809 1 9318 4658 open 0.46 0.004165 1 6875 mmap 0.28 0.002555 3 977 732 execve 0.19 0.001677 2 980 735 stat 0.15 0.001366 1 1966 mprotect 0.09 0.000837 0 1820 read 0.09 0.000784 0 5647 close 0.07 0.000604 0 5215 fstat 0.06 0.000537 1 493 munmap 0.05 0.000465 2 244 clone 0.04 0.000356 1 245 245 access 0.03 0.000287 2 134 newfstatat 0.03 0.000235 1 312 openat 0.02 0.000193 0 743 brk 0.01 0.000082 0 245 arch_prctl 0.01 0.000050 0 134 getdents 0.00 0.000045 0 245 futex 0.00 0.000041 0 491 rt_sigaction 0.00 0.000041 0 246 getrlimit 0.00 0.000040 0 489 244 ioctl 0.00 0.000038 0 591 fcntl 0.00 0.000028 0 204 188 lseek 0.00 0.000024 0 489 set_robust_list 0.00 0.000013 0 245 rt_sigprocmask 0.00 0.000012 0 245 set_tid_address 0.00 0.000000 0 1 uname 0.00 0.000000 0 245 fchdir 0.00 0.000000 0 2 1 statfs ------ ----------- ----------- --------- --------- ---------------- 100.00 0.902284 39085 6803 total
pouze grep
> strace -cf grep -r -i "the brown dog" . % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 40.00 0.000304 2 134 getdents 31.71 0.000241 0 533 read 18.82 0.000143 0 319 6 openat 4.08 0.000031 4 8 mprotect 3.29 0.000025 0 199 193 lseek 2.11 0.000016 0 401 close 0.00 0.000000 0 38 19 open 0.00 0.000000 0 6 3 stat 0.00 0.000000 0 333 fstat 0.00 0.000000 0 32 mmap 0.00 0.000000 0 4 munmap 0.00 0.000000 0 6 brk 0.00 0.000000 0 2 rt_sigaction 0.00 0.000000 0 1 rt_sigprocmask 0.00 0.000000 0 245 244 ioctl 0.00 0.000000 0 1 1 access 0.00 0.000000 0 1 execve 0.00 0.000000 0 471 fcntl 0.00 0.000000 0 1 getrlimit 0.00 0.000000 0 1 arch_prctl 0.00 0.000000 0 1 futex 0.00 0.000000 0 1 set_tid_address 0.00 0.000000 0 132 newfstatat 0.00 0.000000 0 1 set_robust_list ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000760 2871 466 total
Komentáře
- V rozsahu vyhledávání celého souborového systému jsou vidlice zanedbatelné. I / O je to, co chcete snížit.
- Ačkoli se jedná o chybu z OP, srovnání je nesprávné, měli byste odstranit
-r
příznakgrep
při použitífind
. Můžete vidět, že opakovaně prohledával stejné soubory porovnáním počtuopen
, ke kterým došlo. - @qwertzguy, ne,
-r
by měl být neškodný, protože-type f
zaručuje, že žádný z argumentů není adresář. Víceopen()
s je nejpravděpodobnější u ostatních souborů otevřenýchgrep
při každém vyvolání (knihovny, lokalizační data …) ( děkuji za úpravu mé odpovědi btw)
odpověď
Pokud jste na SSD a hledáte čas je zanedbatelný, můžete použít GNU paralelně:
find /path -type f | parallel --gnu --workdir "$PWD" -j 8 " grep -i -r "the brown dog" {} "
Tím se provede až 8 grep procesů současně podle toho, co find
nalezeno.
To bude mlátit jednotku pevného disku, ale SSD by se s tím měl docela dobře vyrovnat.
Odpovědět
V této věci je třeba vzít v úvahu ještě jednu věc.
Bude některý z adresářů, kterými grep bude muset rekurzivně projít, obsahovat více soubory než nastavení nofile vašeho systému? (např. počet otevřených popisovačů souborů, výchozí hodnota je 1024 u většiny linuxových distribucí)
Pokud ano, pak najít je určitě způsob, jak jít, protože některé verze grep vybombarduje seznam argumentů příliš dlouhý chyba, když narazí na adresář s více soubory, než je maximální otevřený soubor zpracovává nastavení.
Jen moje 2 .
Komentáře
- Proč by
grep
vybombardovat? Alespoň s GNU grep, pokud zadáte cestu s koncovým/
a použijete-R
it ‚ Budu jednoduše iterovat adresáři. shell nebude ‚ nic rozšiřovat, pokud nedáte shell-globs. V uvedeném příkladu (/*
) tedy pouze obsah/
hmoty, nikoli podsložek, které budou jednoduše vyjmenovány pomocígrep
, nebyl předán jako argument z prostředí. - Vzhledem k tomu, že OP požadoval rekurzivní vyhledávání (např. “ grep -r -i ‚ hnědý pes ‚ / * „), viděl jsem GNU ‚ s grep (alespoň verze 2.9) vybombarduje pomocí: “ -bash: / bin / grep: Seznam argumentů příliš dlouhý “ pomocí přesného vyhledávání, které OP použil v adresáři, který měl více než 140 000 podadresářů.
-exec {} +
formulář udělá méně vidlic, takže by měl být rychlejší než-exec {} \;
. Možná budete muset přidat-H
(nebo-h
) do možnostígrep
, abyste získali přesně ekvivalentní výstup.-r
nagrep
pro druhý