Questo non sarebbe necessariamente la modifica grep
, anche se probabilmente si potrebbe ottenere una più accurata barra di avanzamento con una tale modifica.
Se si esegue il grepping di "migliaia di file" con una singola chiamata di grep, è molto probabile che si stia utilizzando l'opzione -r
in modo ricorsivo in una struttura di directory.In tal caso, non è nemmeno chiaro che grep
sa quanti file esaminerà, perché credo che inizi a esaminare i file prima che esplori l'intera struttura di directory. Esplorare prima la struttura delle directory probabilmente aumenterebbe il tempo di scansione totale (e, infatti, c'è sempre un costo per produrre rapporti di progresso, motivo per cui poche utility Unix tradizionali fanno questo.)
In ogni caso, un semplice ma leggermente la barra di avanzamento imprecisa potrebbe essere ottenuta costruendo l'elenco completo dei file da scansionare e quindi alimentandoli a grep
in lotti di alcune dimensioni, forse 100, o forse in base alla dimensione totale del batch. I piccoli batch consentirebbero rapporti di avanzamento più accurati, ma aumenterebbero anche il sovraccarico poiché richiederebbero l'avvio del processo in più grep e il tempo di avvio del processo potrebbe essere più di un semplice file. Il report sull'avanzamento verrebbe aggiornato per ogni batch di file, quindi dovresti scegliere una dimensione batch che ti fornisca aggiornamenti regolari senza aumentare troppo il sovraccarico. Basare la dimensione del batch sulla dimensione totale dei file (utilizzando, ad esempio, stat
per ottenere il file) renderebbe il report di avanzamento più preciso ma aggiungerà un costo aggiuntivo per l'avvio del processo.
Un vantaggio di questa strategia è che è possibile eseguire anche due o più greps in parallelo, il che potrebbe accelerare un po 'il processo.
In termini generali, un semplice script (che ha appena divide i file dal conte, non in base alle dimensioni, e che non tenta di parallelizzare).
# Requires bash 4 and Gnu grep
shopt -s globstar
files=(**)
total=${#files[@]}
for ((i=0; i<total; i+=100)); do
echo $i/$total >>/dev/stderr
grep -d skip -e "$pattern" "${files[@]:i:100}" >>results.txt
done
Per semplicità, io uso un globstar (**
) per mettere in sicurezza tutti i file in un array. Se la tua versione di bash è troppo vecchia, puoi farlo collegando l'output di find
, ma non è molto efficiente se hai molti file. Sfortunatamente, non conosco un modo per scrivere un'espressione globstar che corrisponda solo ai file. (**/
corrisponde solo alle directory). Fortunatamente, GNU grep fornisce l'opzione -d skip
che salta silenziosamente le directory. Ciò significa che il conteggio dei file sarà leggermente imprecisa, dal momento che le directory verranno conteggiate, ma probabilmente non fa molta differenza.
Probabilmente vorrai rendere più pulito il rapporto sui progressi utilizzando alcuni codici di console. Quanto sopra è solo per iniziare.
Il modo più semplice per dividere che in diversi processi sarebbe dividere solo l'elenco in diversi segmenti X ed eseguire X diverso per cicli, ciascuno con un diverso punto di partenza. Tuttavia, probabilmente non finiranno tutti allo stesso tempo, quindi non è ottimale. Una soluzione migliore è GNU parallela. Si potrebbe fare qualcosa di simile:
find . -type f -print0 |
parallel --progress -L 100 -m -j 4 grep -e "$pattern" > results.txt
(Qui -L 100
specifica che fino a 100 file dovrebbe essere data a ogni istanza grep, e -j 4
specifica quattro processi paralleli Ho appena tirato quei numeri fuori l'aria, si'. ll probabilmente vuole regolarle.)
Hai mai pensato di utilizzare uno script per farlo? È più semplice che modificare il codice sorgente grep –