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 ditime 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 delfind
, mentre la corrispondenza confind -name
corrisponderebbe solo esattamente (in questo caso). - Sì,
find filename
sarebbe veloce . Ho pensato che fosse un errore di battitura e che lOP significassefind -name filename
. Confind filename
, verrebbe esaminato solofilename
(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
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 chiamatojack
o tutti i nomi nella directory se ‘ è una directory. È ‘ un malinteso su come funzionafind
.
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 difind
…) - @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'
rallentifind
? 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.
find filename
restituirebbe solofilename
sefilename
non fosse di tipo directory (o fosse di tipo directory, ma non aveva alcuna voce in sé)