2008-10-09 17 views
6

Muchas veces tengo que trabajar con directorios que contienen cientos de miles de archivos, haciendo coincidencia de texto, reemplazando, etc. Si voy a la ruta estándar de, por ejemplo¿Cómo manejas el problema "Demasiados archivos" cuando trabajas en Bash?

grep foo * 

consigo el mensaje de error demasiados archivos, por lo que termino haciendo

for i in *; do grep foo $i; done 

o

find ../path/ | xargs -I{} grep foo "{}" 

pero estos son menos óptimo (cree un nuevo proceso grep por cada archivo).

Esto parece más una limitación en el tamaño de los argumentos que los programas pueden recibir, porque el * en el bucle for funciona bien. Pero, en cualquier caso, ¿cuál es la forma correcta de manejar esto?

PD: No me digas que haga grep -r en cambio, lo sé, estoy pensando en herramientas que no tienen una opción recursiva.

Respuesta

8

En las nuevas versiones de findutils, encontrará que puede hacer el trabajo de xargs (incluyendo el comportamiento glomming, de manera que sólo se utilizan tantos procesos grep según sea necesario):

find ../path -exec grep foo '{}' + 

el uso de + en lugar de ; como último argumento desencadena este comportamiento.

+0

¡Un gran consejo! Nunca supe de la opción "+". – mhawke

4

xargs no inicia un nuevo proceso para cada archivo. Agrupa los argumentos. Eche un vistazo a la opción -n para xargs: controla el número de argumentos pasados ​​a cada ejecución del subcomando.

+0

Como mencionó Ry4an, utilizando xargs -I apaga el proceso de lotes. – ephemient

+0

Votación hacia arriba para 'xargs -n' –

0

no puedo ver que

for i in *; do 
    grep foo $i 
done 

funcionaría ya que pensamos que los "demasiados archivos" era una limitación cáscara, por lo tanto, sería un fracaso para el bucle también.

Una vez dicho esto, yo siempre dejo xargs hacer el ronco-obra de la división de la lista de argumentos en trozos manejables así:

find ../path/ | xargs grep foo 

él no se iniciará un proceso por archivo, pero por grupo de archivos.

+0

No, la limitación de" demasiados archivos "se debe a que la longitud de los argumentos del programa que se está ejecutando es de tamaño restringido. "for i in *" nunca abandona el shell actual para ejecutar otro programa, por lo que no puede alcanzar esta limitación. – ephemient

+0

Hacer eco y ampliar el comentario anterior: es un límite en la variable de entorno combinado y el espacio argv común para cualquier invocación de proceso, no un límite de shell. Las asignaciones de memoria de expansiones glob se salen de la pila, no están sujetas a eso, hasta que, a menos que intente poner sus resultados en una línea de comando de un comando externo o en una variable de entorno (variables de shell no exportadas al entorno todavía son de montón, así que bien). –

6

Si hay un riesgo de que los nombres de archivo que contienen espacios, debe acordarse de usar la bandera -print0 encontrar junto con la bandera de -0 a xargs:

find . -print0 | xargs -0 grep -H foo 
+0

Normalmente uso 'xargs -d '\ n'' usando líneas nuevas como separadores, ya que las salidas de salida están separadas por líneas nuevas de forma predeterminada. – ephemient

+0

@ephemient, eso no es seguro, ya que los sistemas de archivos POSIX permiten nuevas líneas dentro de los nombres de archivo. –

+0

¿Inseguro de qué manera? Sí, existe la posibilidad de que grep falle en ciertos nombres de archivo, pero a menos que haya un agujero de seguridad en grep, ¿cómo es inseguro? – JesperE

0

Bueno, tuve los mismos problemas, pero parece que todo lo que se me ocurrió ya está mencionado. En su mayoría, tenía dos problemas. Hacer globs es costoso, hacer ls en un directorio de millones de archivos tarda una eternidad (más de 20 minutos en uno de mis servidores) y hacer ls * en un directorio de millones de archivos tarda una eternidad y falla con un error de "lista de argumentos demasiado larga".

find /some -type f -exec some command {} \; 

parece ayudar con ambos problemas. Además, si necesita realizar operaciones más complejas en estos archivos, puede considerar guiar sus cosas en múltiples hilos. Aquí hay un iniciador de Python para crear scripts de CLI. http://www.ibm.com/developerworks/aix/library/au-pythocli/?ca=dgr-lnxw06pythonunixtool&S_TACT=105AGX59&S_CMP=GR

+0

Usando find -exec grep foo ';' tiene el mismo problema que la solución original, ya que ejecuta una instancia individual de grep para cada archivo. –

Cuestiones relacionadas