Cómo grep miles de archivos en un directorio para cientos de cadenas en un archivo

11

Estoy tratando de componer una grepdeclaración y me está matando. También estoy cansado de recibir el arguments list too longerror. Tengo un archivo, llamémoslo subset.txt. Contiene cientos de líneas con cadenas específicas como MO43312948. En mi directorio de objetos tengo miles de archivos y necesito copiar todos los archivos que contienen las cadenas enumeradas en subset.txtotro directorio.

Estaba tratando de comenzar con esto para devolver los archivos coincidentes del directorio de objetos.

grep -F "$(subset.txt)" /objects/*

Sigo recibiendo `bash: / bin / grep: Lista de argumentos demasiado larga``

Revlis
fuente
66
¿Por qué has puesto "$(subset.txt)"el comando así? Esa es la sustitución de comandos , lo que hará que su shell se ejecute subset.txt (como si fuera un comando o script).
JigglyNaga

Respuestas:

23

Puede pasar un directorio como un objetivo para grepcon -Ry un archivo de patrones de entrada con -f:

  -f FILE, --file=FILE
          Obtain patterns from FILE, one per line.  If this option is used
          multiple  times  or  is  combined with the -e (--regexp) option,
          search for all patterns given.  The  empty  file  contains  zero
          patterns, and therefore matches nothing.

   -R, --dereference-recursive
          Read all files under each directory,  recursively.   Follow  all
          symbolic links, unlike -r.

Entonces, estás buscando:

grep -Ff subset.txt -r objects/

Puede obtener la lista de archivos coincidentes con:

grep -Flf subset.txt -r objects/

Entonces, si su lista final no es demasiado larga, simplemente puede hacer:

 mv $(grep -Flf subset.txt -r objects/) new_dir/

Si eso devuelve un argument list too longerror, use:

grep -Flf subset.txt -r objects/ | xargs -I{} mv {} bar/

Y si los nombres de sus archivos pueden contener espacios u otros caracteres extraños, use (suponiendo GNU grep):

grep -FZlf subset.txt -r objects/ | xargs -0I{} mv {} bar/

Finalmente, si desea excluir archivos binarios, use:

grep -IFZlf subset.txt -r objects/ | xargs -0I{} mv {} bar/
terdon
fuente
… O para evitar potencialmente miles de mvinvocaciones con un argumento cada una: ... | xargs -0 mv -t bar/(suponiendo que su mvsoporte sea compatible con la -topción).
David Foerster
11

utilizar

grep -F -f subset.txt 

decirle a grep que lea del subset.txtarchivo.

puede usar find para recorrer el archivo.

find . -type f -exec grep -F -f subset.txt {} \;

o

find . -type f -exec grep -F -f subset.txt {}  +
Archemar
fuente
¿Alguna ventaja de usar en findlugar de -rotra que hacer filtrado adicional?
phk
1
@phk grep -rbusca en enlaces simbólicos a archivos regulares, lo que puede o no ser deseable (si apuntan dentro del mismo árbol, está buscando el mismo archivo dos veces; si apuntan afuera, está buscando un archivo que puede o no ser deseado).
Gilles 'SO- deja de ser malvado'
Las versiones modernas de greptienen opciones para controlar su interacción con enlaces simbólicos ( man greppara determinar los detalles del sistema actual). Un recursivo grepserá mucho más rápido que ejecutarse grepindividualmente en cada archivo a través de find.
Perry
1
@Perry, ¿estás seguro de eso? ¿Por qué? Además, tenga en cuenta que esta respuesta está utilizando -exec +, por lo que agrupará los archivos y no ejecutará un grep por archivo.
terdon
Estoy corregido, no estaba al tanto de las diferentes semánticas de -exec {} +vs -exec {} \;... aprendes algo nuevo todos los días (todavía no veo ninguna razón por la cual un solo recursivo grepno sea más rápido que varios greps ejecutados finddebido a la creación de procesos y al análisis de patrones por encima de la cabeza, pero yo no tengo números específicos para respaldar eso).
Perry
3

Si desea acelerar grep aún más, puede establecer la configuración regional en su shell antes de ejecutarlo, es decir, usar "LC_ALL = c". Esto se heredará en grep y deshabilitará el procesamiento Unicode cuando no sea necesario y, en algunos casos, puede acelerar dramáticamente grep. Un gran blog que documenta esto se puede encontrar en http://www.inmotionhosting.com/support/website/ssh/speed-up-grep-searches-with-lc-all . Este truco también puede acelerar los scripts de shell bash, no solo grep.

Erik Brandsberg
fuente