Grep in un paio di migliaia di file


13

Ho una directory con 26000 file cca e ho bisogno di grep in tutti questi file. Il problema è che ne ho bisogno il più velocemente possibile, quindi non è l'ideale creare script in cui grep prenderà il nome di un file dal comando find e scriverà le corrispondenze nel file. Prima del problema "Elenco argomenti troppo lungo" ci sono voluti circa 2 minuti per eseguire il grep in tutti questi file. Qualche idea su come farlo? modifica: esiste uno script che crea sempre nuovi file, quindi non è possibile mettere tutti i file in directory diverse.


1
utilizzare findcon xargsogrep -R
Eddy_Em

Funziona bene, ma ci vogliono 10 minuti ...
user2778979

Risposte:


19

Con find:

cd /the/dir
find . -type f -exec grep pattern {} +

( -type fè solo per cercare in file regolari (escludendo anche i collegamenti simbolici anche se puntano a file regolari). Se si desidera cercare in qualsiasi tipo di file tranne le directory (ma attenzione ci sono alcuni tipi di file come fifos o / dev / zero che di solito non vuoi leggere), sostituiscilo -type fcon quello specifico di GNU ! -xtype d( -xtype dcorrisponde a file di tipo directory dopo la risoluzione del link simbolico)).

Con GNU grep:

grep -r pattern /the/dir

(ma attenzione che a meno che non si disponga di una versione recente di GNU grep, questo seguirà i collegamenti simbolici quando si scende nelle directory). I file non regolari non verranno cercati se non aggiungi -D readun'opzione. Le versioni recenti di GNU non grepeffettueranno comunque ricerche all'interno dei symlink.

Le versioni molto vecchie di GNU findnon supportavano la {} +sintassi standard , ma lì si poteva usare il non standard:

cd /the/dir &&
  find . -type f -print0 | xargs -r0 grep pattern

È probabile che le prestazioni siano associate all'I / O. Quello è il tempo di fare la ricerca sarebbe il tempo necessario per leggere tutti quei dati dalla memoria.

Se i dati si trovano su un array di dischi ridondante, la lettura di più file alla volta potrebbe migliorare le prestazioni (e altrimenti degradarle). Se le prestazioni non sono associate all'I / O (perché ad esempio tutti i dati sono nella cache) e si dispone di più CPU, anche i concorrenti grepspossono essere d'aiuto. Puoi farlo con xargsl' -Popzione GNU .

Ad esempio, se i dati si trovano su un array RAID1 con 3 unità o se i dati sono nella cache e si dispone di 3 CPU il cui tempo libero:

cd /the/dir &&
  find . -type f -print0 | xargs -n1000 -r0P3 grep pattern

(qui usando -n1000per generare un nuovo grepogni 1000 file, fino a 3 in esecuzione alla volta).

Tuttavia, se l'output di grepviene reindirizzato, si otterrà un output interfogliato in modo errato dai 3 grepprocessi, nel qual caso si consiglia di eseguirlo come:

find . -type f -print0 | stdbuf -oL xargs -n1000 -r0P3 grep pattern

(su un recente sistema GNU o FreeBSD) o usa l' --line-bufferedopzione di GNU grep.

Se patternè una stringa fissa, l'aggiunta -Fdell'opzione potrebbe migliorare le cose.

Se non si tratta di dati carattere multibyte o se per la corrispondenza di quel modello, non importa se i dati sono carattere multibyte oppure no, quindi:

cd /the/dir &&
  LC_ALL=C grep -r pattern .

potrebbe migliorare significativamente le prestazioni.

Se finisci per fare spesso tali ricerche, allora potresti voler indicizzare i tuoi dati usando uno dei tanti motori di ricerca là fuori.


3

26000 file in una singola directory sono molti per la maggior parte dei filesystem. È probabile che la lettura di questa grande directory richieda una parte significativa del tempo. Valuta di dividerlo in directory più piccole con solo poche centinaia di file ciascuna.

La chiamata findnon può spiegare prestazioni scadenti a meno che non si commetta un errore. È un modo rapido per attraversare una directory e per assicurarsi di non rischiare di tentare di eseguire una riga di comando troppo lunga. Assicurati di utilizzare -exec grep PATTERN {} +, che comprime il maggior numero di file possibile per invocazione di comandi e non -exec grep PATTERN {} \;, che viene eseguito grepuna volta per file: l'esecuzione del comando una volta per file è probabilmente molto più lenta.


Grazie, google qualcosa a riguardo e probabilmente lo dividerò. Ho fatto esattamente quello di cui stai scrivendo e ci sono voluti 3 volte di più di un solo grep ...
user2778979

Gilles, stai dicendo che le prestazioni differirebbero significativamente per 26.000 file in una directory rispetto a 26.000 file distribuiti su, diciamo, 100 directory?
user001

1
@ user001 Sì. Quanto differiscono dipende dal filesystem e possibilmente dall'archiviazione sottostante, ma mi aspetto che qualsiasi filesystem sia misurabile in modo più veloce con 260 file in ciascuna delle 100 directory rispetto ai 26000 file in una singola directory.
Gilles 'SO- smetti di essere malvagio' il

Grazie per il chiarimento. Ho chiesto a un follow-up domanda su questo punto, al fine di comprendere la base per la discrepanza.
user001

0

Se hai bisogno di grep TUTTI i file più volte (come hai detto, eseguendo uno script) Suggerirei di esaminare i dischi ram, copiare tutti i file lì e quindi grep i file più volte, questo accelererà la tua ricerca di un fattore di almeno 100x.

Hai solo bisogno di abbastanza ariete. Altrimenti, dovresti cercare di indicizzare i file, ad es. in lucene o in un database nosql e quindi eseguire query su questo.


Come notato altrove, questo non aiuta il fatto che ci sono troppi file per eseguire un grepcontro. C'è anche il punto che: "esiste uno script che crea sempre nuovi file, quindi non è possibile mettere tutti i file in directory diverse".
Jeff Schaller

-2

Tutti i file nella directory

grep 'search string' *

con ricorsivamente

grep -R 'search string' *

Ti interessa elaborare il -1?
Markus,

4
Non ho votato in negativo, ma ci sono alcuni problemi con il tuo: l'OP ha menzionato una "lista arg troppo lunga", che il tuo primo non risolverà ed è probabilmente ciò che l'OP stava facendo prima. Il secondo non aiuta neanche a questo proposito (avrebbe aiutato se tu avessi usato .invece di *). *escluderà i file punto (sebbene con -R, non quelli nelle directory ricorrenti). -R al contrario di -r segue i symlink anche con le recenti versioni di GNU grep. Avrai anche un problema con i file nella directory corrente il cui nome inizia con-
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.