Hvilket er mere effektivt til at finde hvilke filer i et helt filsystem der indeholder en streng: rekursiv grep eller find med grep i en exec-sætning? Jeg antager, at find ville være mere effektivt, fordi du i det mindste kan filtrere noget, hvis du kender filtypen eller en regex, der matcher filnavnet, men når du kun kender -type f, hvilket er bedre ? GNU grep 2.6.3; find (GNU findutils) 4.4.2

Eksempel:

grep -r -i "the brown dog" /

find / -type f -exec grep -i "the brown dog" {} \;

Kommentarer

  • Matematik / datalogi / algoritmeeffektivitet ins ‘ t opinion baseret.
  • Tjek denne. Selvom det ikke er rekursivt, vil det give en forståelse af, hvad der er bedre. unix.stackexchange.com/questions/47983/…
  • @AvinashRaj he ‘ beder ikke om mening. Han ‘ ‘ spørger, hvad der er mere effektivt og / eller hurtigere , ikke hvilken der er ” bedre “. Dette er et perfekt svar, der har et enkelt, specifikt svar, der afhænger af, hvordan disse to programmer gør deres job, og hvad du præcist giver dem at søge igennem.
  • Bemærk, at -exec {} + form vil gøre færre gafler, så det skal være hurtigere end -exec {} \;. Du skal muligvis tilføje -H (eller -h) til grep mulighederne for at få nøjagtigt tilsvarende output.
  • Du ville sandsynligvis ikke ‘ t have -r mulighed på grep til den anden

Svar

Jeg er ikke sikker:

grep -r -i "the brown dog" /* 

er virkelig hvad du mente. Det ville betyde grep rekursivt i alle de ikke-skjulte filer og dirs i / (men stadig se inde i skjulte filer og dirs inde i dem).

Forudsat at du mente:

grep -r -i "the brown dog" / 

Et par ting at bemærke:

  • Ikke alle grep implementeringer understøtter -r. Og blandt dem der gør det, adfærd adskiller sig: nogle følger symlinks til mapper, når de krydser katalogtræet (hvilket betyder, at du måske ender med at se se ofte i den samme fil eller endda køre i uendelige sløjfer), vil nogle ikke. Nogle vil se inde i enhedsfiler (og det vil tage lang tid i /dev/zero for eksempel) eller rør eller binære filer … nogle vil ikke.
  • Det er effektivt, da grep begynder at kigge ind i filer, så snart det opdager dem. Men mens det ser i en fil, er det ikke længere på udkig efter flere filer at søge i (som er sandsynligvis lige så godt i de fleste tilfælde)

Din:

find / -type f -exec grep -i "the brown dog" {} \; 

(fjernet -r hvilket ikke giver mening her) er frygtelig ineffektivt, fordi du kører en grep pr. fil. ; bør kun bruges til kommandoer, der kun accepterer et argument. Desuden her, fordi grep kun ser i en fil, vil den ikke udskrive filnavnet, så du ved ikke, hvor kampene er.

Dig ” ser ikke inde i enhedsfiler, rør, symlinks …, du følger ikke symlinks, men du ser stadig potentielt inden i ting som /proc/mem.

find / -type f -exec grep -i "the brown dog" {} + 

ville være meget bedre, fordi så få grep kommandoer som muligt ville blive kørt. Du får filnavnet, medmindre den sidste kørsel kun har én fil. Til det er det bedre at bruge:

find / -type f -exec grep -i "the brown dog" /dev/null {} + 

eller med GNU grep:

find / -type f -exec grep -Hi "the brown dog" {} + 

Bemærk at grep først startes find har fundet nok filer til at tygge på, så der vil være en vis forsinkelse. Og find vil ikke fortsætte med at søge efter flere filer, før den forrige grep er vendt tilbage. Tildeling og videregivelse af listen over store filer har en vis (sandsynligvis ubetydelig) indvirkning, så alt i alt vil det sandsynligvis være mindre effektiv end en grep -r, der ikke følger symlink eller ser ud inde i enheder.

Med GNU-værktøjer:

find / -type f -print0 | xargs -r0 grep -Hi "the brown dog" 

Som ovenfor, så få grep forekomster som muligt køres, men find vil fortsætte med at lede efter flere filer, mens den første grep indkaldelse kigger inden i den første batch. Det kan dog eller ikke være en fordel.For eksempel med data, der er gemt på rotationsharddiske, find og grep, der får adgang til data, der er gemt forskellige steder på disken, sænker disken kapacitet ved at få diskhovedet til at bevæge sig konstant. I en RAID-opsætning (hvor find og grep kan få adgang til forskellige diske) eller på SSDer, kan det gøre en positiv forskel.

I en RAID-opsætning kan kørsel af flere samtidige grep påkald også forbedre tingene. Stadig med GNU-værktøjer på RAID1-lagring med 3 diske,

find / -type f -print0 | xargs -r0 -P2 grep -Hi "the brown dog" 

kan øge ydeevnen betydeligt. Bemærk dog, at den anden grep kun startes, når der er fundet nok filer til at udfylde den første grep kommando. Du kan tilføje en -n mulighed til xargs for at dette skal ske hurtigere (og videregive færre filer pr. grep invocation).

Bemærk også, at hvis du “omdirigerer xargs output til alt andet end en terminalenhed, så greps s begynder at buffere deres output, hvilket betyder, at output fra disse grep s sandsynligvis vil blive forkert sammenflettet. Du skal bruge stdbuf -oL (hvor de er tilgængelige som på GNU eller FreeBSD) på dem for at omgå det (du kan stadig have problemer med meget lange linjer (typisk> 4KiB)) eller har hver til at skrive deres output i en separat fil og sammenkæde dem alle i sidste ende.

Her er den streng, du leder efter, rettet (ikke en regexp), så brug af -F kan muligvis gøre en forskel (usandsynligt som grep implementeringer ved, hvordan man optimerer det allerede).

En anden ting, der kan Det ville gøre en stor forskel at rette lokaliteten til C, hvis du “er i et multi-byte-sprog:

find / -type f -print0 | LC_ALL=C xargs -r0 -P2 grep -Hi "the brown dog" 

For at undgå at kigge ind /proc, /sys …, brug -xdev og angiv de filsystemer, du vil søge i:

LC_ALL=C find / /home -xdev -type f -exec grep -i "the brown dog" /dev/null {} + 

Eller beskær de stier, du vil ekskludere eksplicit:

LC_ALL=C find / \( -path /dev -o -path /proc -o -path /sys \) -prune -o \ -type f -exec grep -i "the brown dog" /dev/null {} + 

Kommentarer

  • Jeg ‘ t formoder, at nogen kan pege mig på en ressource – eller forklare – hvad {} og + betyder. Der ‘ er intet, jeg kan se på mandsiderne til exec, grep eller finde i Solaris-feltet, jeg ‘ bruger. Er kun skallen sammenkædende filnavne og videregiver dem til grep?
  • @Poldie, at ‘ forklares tydeligt i beskrivelsen af -exec predikat i Solaris-mandsiden
  • Ah, ja. Jeg var ikke ‘ undslippe min {char mens jeg søgte på mandsiden. Dit link er bedre; Jeg finder mandesider forfærdelige at læse.
  • RAID1 m / 3 diske? Hvor mærkeligt …
  • @tink, ja RAID1 er på 2 eller flere diske. Med 3 diske sammenlignet med 2 diske øger du redundans og læser ydeevne, mens skriveydelse er omtrent den samme. Med 3 diske i modsætning til 2 betyder det, at du også kan rette fejl, som når en smule vender på en af kopierne, er du ‘ i stand til at fortælle, hvad der er rigtigt ved at markere alle 3 kopier, mens du med 2 diske kan ‘ ikke rigtig fortælle det.

Svar

Hvis * i grep -opkaldet ikke er vigtigt for dig, bør den første være mere effektiv, da kun en forekomst af grep er startet, og gafler er ikke gratis. I de fleste tilfælde vil det være hurtigere selv med * men i kanttilfælde sorteringen kan vende det.

Der kan være andre findgrep strukturer, der fungerer bedre især med mange små Læsning af store mængder filindgange og inoder på én gang kan give en forbedring af ydeevnen på roterende medier.

Men lad os se på syscall-statistikken:

find

> 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 

kun 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 

Kommentarer

  • På skalaen til søgning i et helt filsystem er gafler ubetydelige. I / O er det, du vil reducere.
  • Selvom det er en fejl fra OP, er sammenligningen forkert, skal du fjerne -r -flagget for grep når du bruger find. Du kan se, at det søgte igen og igen de samme filer ved at sammenligne antallet af open, der skete.
  • @qwertzguy, nej, -r bør være harmløs, da -type f garanterer, at ingen af argumenterne er mapper. De flere open() s er mere sandsynlige ned til de andre filer, der åbnes af grep ved hver indkaldelse (biblioteker, lokaliseringsdata …) ( tak for redigeringen på mit svar btw)

Svar

Hvis du er på en SSD og søger tid er ubetydelig, kan du bruge GNU parallel:

find /path -type f | parallel --gnu --workdir "$PWD" -j 8 " grep -i -r "the brown dog" {} " 

Dette udfører op til 8 grep-processer på samme tid baseret på hvad find fundet.

Dette vil kaste en harddisk, men en SSD skal klare det ret godt.

Svar

En ting mere at overveje på denne er som følger.

Vil nogen af de mapper, som grep skal rekursivt gennemgå, indeholde mere filer end dit systems “ nofile indstilling? (f.eks. antal åbne filhåndtag, standard er 1024 på de fleste linux distroer)

Hvis ja, så er find bestemt den rigtige vej, da visse versioner af grep vil bombe ud med en Argumentliste for lang fejl, når den rammer en mappe med flere filer end den maksimale åbne fil håndterer indstilling.

Bare min 2 ¢.

Kommentarer

  • Hvorfor ville grep bombe ud? I det mindste med GNU grep, hvis du giver en sti med efterfølgende / og bruger -R det ‘ Jeg gentager simpelthen gennem telefonbøgerne. -skallen er ikke ‘ t vil udvide noget, medmindre du giver shell-globs. Så i det givne eksempel (/*) er det kun indholdet af /, der betyder noget, ikke af undermapperne, som simpelthen vil blive opregnet af grep, ikke sendt som argument fra skallen.
  • Nå, i betragtning af at OP spurgte om at søge rekursivt (f.eks. ” grep -r -i ‘ den brune hund ‘ / * “), har jeg set GNU ‘ s grep (i det mindste version 2.9) bomber ud med: ” -bash: / bin / grep: Argumentlisten er for lang ” ved hjælp af den nøjagtige søgning, som OP anvendte i et bibliotek, der havde over 140.000 underkataloger.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *