Ho provato entrambi i comandi e il comando find | grep "filename" è molte volte più lento del semplice find "filename".

Quale sarebbe una spiegazione adeguata per questo comportamento?

Commenti

  • Tu stanno elencando ogni file con find e quindi passando i dati a grep per lelaborazione. Con find usato su di esso ‘ ti manca il passaggio di passare ogni file elencato a grep per analizzare loutput. Questo sarà quindi più veloce.
  • Più lento in che senso? Il completamento dei comandi richiede un tempo diverso?
  • Posso ‘ riprodurlo localmente. Semmai, time find "$HOME" -name '.profile' segnala un tempo più lungo di time find "$HOME" | grep -F '.profile'. (17s contro 12s).
  • @JenniferAnderson Ho eseguito entrambi ripetutamente. I 17 e 12 secondi sono medie. E sì, la variante grep corrisponderà in qualsiasi punto del find, mentre la corrispondenza con find -name corrisponderebbe solo esattamente (in questo caso).
  • Sì, find filename sarebbe veloce . Ho pensato che fosse un errore di battitura e che lOP significasse find -name filename. Con find filename, verrebbe esaminato solo filename (e nientaltro).

Rispondi

(presumo GNU find qui)

Usando solo

find filename 

sarebbe veloce, perché restituirebbe solo filename o i nomi allinterno di filename se è “una directory, o un errore se quel nome non esisteva nella directory corrente. È “unoperazione molto rapida, simile a ls filename (ma ricorsiva se filename è una directory).

In al contrario,

find | grep filename 

consentirebbe a find di generare un elenco di tutti nomi da la directory corrente e quella inferiore, che grep filtrerebbe. Questa sarebbe ovviamente unoperazione molto più lenta.

Presumo che ciò che era effettivamente si intendeva

find . -type f -name "filename" 

Questo dovrebbe cercare filename come nome di un normale file ovunque la directory corrente o quella inferiore.

Sarà veloce (o relativamente veloce) come find | grep filename, ma grep la soluzione corrisponderebbe a filename con il percorso completo di ciascun nome trovato, in modo simile a ciò che -path "*filename*" farebbe con find.


La confusione deriva da un malinteso su come find funziona.

Lutility accetta un numero di percorsi e restituisce tutti i nomi sotto questi percorsi.

Puoi quindi limitare i nomi restituiti utilizzando vari test che possono agire sul nome del file, il percorso, il timestamp, la dimensione del file, il tipo di file, ecc.

Quando dici

find a b c 

chiedi a find di elencare tutti i nomi disponibili nei tre percorsi a, b e c. Se questi sono nomi di file normali nella directory corrente, verranno restituiti. Se uno di questi è il nome di una directory, verrà restituito insieme a tutti gli altri nomi allinterno di quella directory.

Quando lo faccio

find . -type f -name "filename" 

Questo genera un elenco di tutti i nomi nella directory corrente (.) e di seguito. Quindi limita i nomi a quelli dei file normali, cioè non directory ecc., Con -type f. Poi cè unulteriore restrizione ai nomi che corrispondono a filename utilizzando -name "filename". La stringa filename potrebbe essere un modello di globbing del nome di file, come *.txt (ricordati di citarla!).

Esempio:

Quanto segue sembra “trovare” il file chiamato .profile nella mia home directory:

$ pwd /home/kk $ find .profile .profile 

Ma in realtà, restituisce solo tutti i nomi nel percorso .profile (cè un solo nome, e quello è di questo file).

Quindi cd sali di un livello e riprovo:

$ cd .. $ pwd /home $ find .profile find: .profile: No such file or directory 

Il find il comando ora non riesce a trovare alcun percorso chiamato .profile.

Tuttavia, se riesco a cercare nella directory corrente e quindi restringo i nomi restituiti solo a .profile , trova anche da lì:

$ pwd /home $ find . -name ".profile" ./kk/.profile 

Commenti

  • find filename restituirebbe solo filename se filename non fosse di tipo directory (o fosse di tipo directory, ma non aveva alcuna voce in sé)

Risposta

Spiegazione non tecnica: Alla ricerca di Jack in mezzo alla folla è più veloce che cercare tutti in mezzo alla folla ed eliminare tutti dalla considerazione tranne Jack.

Commenti

  • Il problema è che lOP si aspetta che Jack lo faccia sii lunica persona nella folla. Se lo è, sono ‘ fortunati. find jack elencherà jack se ‘ sa un file chiamato jack o tutti i nomi nella directory se ‘ è una directory. È ‘ un malinteso su come funziona find.

Risposta

Non ho ancora capito il problema, ma posso fornire ulteriori informazioni.

Come per Kusalananda la chiamata find | grep è chiaramente più veloce sul mio sistema, il che non ha molto senso. Allinizio ho pensato a qualche tipo di problema di buffering; quella scrittura sulla console rallenta il tempo per la successiva chiamata di sistema per la lettura del nome del file successivo. La scrittura su una pipe è molto veloce: circa 40MiB / s anche per scritture a 32 byte (sul mio sistema piuttosto lento; 300 MiB / s per una dimensione di blocco di 1MiB). Pertanto ho assunto che find possa leggere dal file system più velocemente durante la scrittura su una pipe (o file) in modo che le due operazioni di lettura dei percorsi dei file e scrittura sulla console possano essere eseguite in parallelo ( che find come processo a thread singolo non può fare da solo.

It “s find

Confronto delle due chiamate

:> time find "$HOME"/ -name "*.txt" >/dev/null real 0m0.965s user 0m0.532s sys 0m0.423s 

e

:> time find "$HOME"/ >/dev/null real 0m0.653s user 0m0.242s sys 0m0.405s 

mostra che find fa qualcosa di incredibilmente stupido (qualunque cosa sia). risulta essere piuttosto incompetente nellesecuzione di -name "*.txt".

Potrebbe dipendere dal rapporto input / output

Potresti pensare che find -name vinca se cè molto poco da scrivere. Ma è solo più imbarazzante per find. Perde anche se non cè niente da scrivere rispetto a 200.000 file (13 M di dati pipe) per grep:

time find /usr -name lwevhewoivhol 

find può raggiungere la velocità di grep, sebbene

Si scopre che find “s stupidità con name non si estende ad altri test. Utilizza invece unespressione regolare e il problema è risolto:

:> time find "$HOME"/ -regex "\.txt$" >/dev/null real 0m0.679s user 0m0.264s sys 0m0.410s 

Immagino che questo possa essere considerato un bug. Qualcuno disposto a presentare una segnalazione di bug? La mia versione è find (GNU findutils) 4.6.0

Commenti

  • Quanto sono ripetibili i tuoi tempi? Se hai eseguito prima il test -name, potrebbe essere stato più lento perché i contenuti della directory non venivano memorizzati nella cache. (Quando si testano -name e -regex trovo che impieghino più o meno lo stesso tempo, almeno una volta che leffetto cache è stato preso in considerazione. Di ovviamente potrebbe essere solo una versione diversa di find …)
  • @psmears Ovviamente ho eseguito questi test diverse volte. Il problema del caching è stato menzionato anche nei commenti alla domanda prima della prima risposta. La mia versione di find è find (GNU findutils) 4.6.0
  • Perché è sorprendente che laggiunta di -name '*.txt' rallenti find? Deve fare del lavoro extra, testare ogni nome di file.
  • @Barmar Da un lato questo lavoro extra può essere fatto molto velocemente. Daltra parte questo lavoro extra fa risparmiare altro lavoro. find deve scrivere meno dati. E scrivere su una pipe è unoperazione molto più lenta.
  • Scrivere su un disco è molto lenta, scrivere su una pipe non è poi così male, copia solo su un buffer del kernel. Nota che nel tuo primo test, scrivere altro in /dev/null in qualche modo utilizzava meno tempo di sistema.

Risposta

Avviso : presumo che tu intenda find . -name filename (altrimenti, “stai cercando cose diverse; find filename in realtà cerca in un percorso chiamato nomefile , che potrebbe non contenere quasi nessun file, quindi uscire molto rapidamente).


Supponi di avere una directory contenente cinquemila file. Sulla maggior parte dei filesystem, questi file sono effettivamente archiviati in una struttura ad albero , che consente di individuare rapidamente qualsiasi file.

Quindi, quando chiedi a find di individuare un file il cui nome richiede solo il controllo, find chiederà per quel file, e solo quel file, al filesystem sottostante, che leggerà pochissime pagine dalla memoria di massa. Quindi, se il filesystem vale il suo sale, questa operazione verrà eseguita molto più velocemente di attraversando lintero albero per recuperare tutte le voci.

Quando chiedi find semplice, tuttavia è esattamente quello che fai, attraversi lintero albero, leggendo. Ogni. Singolo. Entrata. Con grandi directory, questo potrebbe essere un problema (è esattamente il motivo per cui diversi software, avendo bisogno di memorizzare molti file su disco, creeranno “alberi di directory” profondi due o tre componenti: in questo modo, ogni singola foglia deve contenere solo meno file) .

Risposta

Supponiamo che il file / john / paul / george / ringo / beatles esista e il file che stai cercando si chiama “stones”

find / stones 

find confronterà “beatles” con “stones” e lo rilascerà quando “s” e “b” non corrispondono .

find / | grep stones 

In questo caso find passerà “/ john / paul / george / ringo / beatles” a grep e grep wil Devo farmi strada attraverso lintero percorso prima di determinare se è una corrispondenza.

grep sta quindi facendo molto più lavoro ed è per questo che ci vuole più tempo

Commenti

  • Hai provato?
  • Il costo dei confronti di stringhe (estremamente semplice ed economico) è completamente sminuito dal costo IO (o solo syscall se memorizzato nella cache) delle ricerche di directory.
  • grep non è ‘ un confronto di stringhe, il suo confronto di espressioni regolari il che significa che deve farsi strada attraverso lintera stringa finché non trova una partita o arriva alla fine. Le ricerche di directory sono le stesse, non importa cosa.
  • @Paranoid Hm, di quale versione di find stai parlando? A quanto pare, ‘ non somiglia a find che ‘ sono abituato a Debian.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *