2008-11-20 21 views

Respuesta

109

El trabajo de interpretar el símbolo de canalización como una instrucción para ejecutar varios procesos y tubo de la salida de un proceso en la entrada de otro proceso es responsabilidad del shell (/ bin/sh o equivalente).

En el ejemplo, usted puede optar por utilizar la cáscara de nivel superior para llevar a cabo la tubería de este modo:

find -name 'file_*' -follow -type f -exec zcat {} \; | agrep -dEOE 'grep' 

En términos de eficiencia esto da lugar a costes de una invocación de encontrar, numerosas invocaciones de zcat, y uno invocación de agrep.

Esto daría como resultado que solo se generara un único proceso de agrep que procesara toda la producción producida por numerosas invocaciones de zcat.

Si por alguna razón desea invocar agrep varias veces, que puede hacer:

find . -name 'file_*' -follow -type f \ 
    -printf "zcat %p | agrep -dEOE 'grep'\n" | sh 

Esto construye una lista de comandos que utilizan tubos de ejecutar, a continuación, envía estos a un nuevo shell para ser ejecutado en realidad . (Omitir el final "| sh" es una buena forma de depurar o realizar ejecuciones en seco de líneas de comando como esta.)

En términos de eficiencia, esto resulta en una invocación de find, una invocación de sh, numerosas invocaciones de zcat y numerosas invocaciones de agrep.

La solución más eficiente en términos de número de llamadas al comando es la sugerencia de Paul Tomblin:

find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep' 

... que cuesta una invocación de encontrar, una invocación de xargs, unos invocaciones de zcat y una invocación de agrep.

+1

Otra ventaja de xargs es que puedes acelerarlo con la CPU de múltiples núcleos incluso más, usando el interruptor -P (-P 0). – flolo

+0

Sí, el P swich es de hecho una buena manera de acelerar la ejecución en general. Desafortunadamente, se corre el riesgo de que la salida de los procesos zcat paralelos se canalice en agrep intercalado, lo que afectaría el resultado. Este efecto se puede demostrar usando: echo -e "1 \ n2" | xargs -P 0 -n 1 sí | uniq –

+0

@Adam, hice su cambio sugerido. –

13
find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep' 
+0

la esperanza de evitar -print y xargs por razones de eficiencia. Tal vez ese es realmente mi problema: find no puede manejar comandos canalizados a través de -exec – someguy

+0

Esto no funciona con archivos con espacios en sus nombres; arreglar, reemplazar -print con -print0 y agregar la opción -0 a xargs –

+2

@someguy - ¿Qué? ¿Evitar xargs por razones de eficiencia? Llamar a una instancia de zcat y pasarle una lista de archivos múltiples es * mucho * más eficiente que ejecutar una nueva instancia para cada archivo encontrado. –

190

la solución es fácil: ejecutar a través de sh

... -exec sh -c "zcat {} | agrep -dEOE 'grep' " \; 
+13

Lo que el OP intentaba lograr se puede cumplir con las sugerencias anteriores, pero este es el que realmente responde la pregunta. Hay razones para hacerlo de esta manera: el ejecutor es mucho más poderoso que simplemente operar en los archivos devueltos por find, especialmente cuando se combina con la prueba. Por ejemplo: find geda-gaf/-type d -exec bash -c 'DIR = {}; [[$ (find $ DIR -maxdepth 1 | xargs grep -i spice | wc -l) -ge 5]] && echo $ DIR '\; Devolverá todos los directorios en la ruta de búsqueda que contengan más de 5 líneas en total entre todos los archivos en ese directorio que contenga la palabra spice – swarfrat

+2

La mejor respuesta. Expandir todo el resultado (como sugieren otras respuestas) no es lo mismo que grep cada archivo. Consejo: en lugar de sh, puedes usar cualquier otro shell que quieras (lo intenté con bash y está funcionando bien). – pagliuca

+1

Asegúrese de no pasar por alto la opción '-c'. De lo contrario, obtendrá un mensaje de error desconcertante 'No such file or directory'. – asmaier

8

También puede canalizar a un while bucle que puede realizar varias acciones en el archivo que find localiza. Así que aquí está uno para buscar en jar archivos para un archivo de clase Java dada en carpeta con una gran distribución de jar archivos

find /usr/lib/eclipse/plugins -type f -name \*.jar | while read jar; do echo $jar; jar tf $jar | fgrep IObservableList ; done 

el punto clave es que el bucle while contiene varios comandos que hacen referencia a la aprobada en nombre de archivo separado por punto y coma y estos comandos pueden incluir tuberías. Entonces, en ese ejemplo hago eco del nombre del archivo coincidente y, luego, enumero lo que está en el filtrado del archivo para un nombre de clase determinado. La salida será similar a:

/usr/lib/eclipse/plugins/org.eclipse.core.contenttype.source_3.4.1.R35x_v20090826-0451.jar /usr/lib/eclipse/plugins/org.eclipse.core .databinding.observable_1.2.0.M20090902-0800.jar org/eclipse/core/enlace de datos/observable/lista/IObservableList .class /usr/lib/eclipse/plugins/org.eclipse.search.source_3.5.1. r351_v20090708-0800.jar /usr/lib/eclipse/plugins/org.eclipse.jdt.apt.core.source_3.3.202.R35x_v20091130-2300.jar /usr/lib/eclipse/plugins/org.eclipse.cvs.source_1.0.400.v201002111343.jar /usr/lib/eclipse/plugins/org.eclipse.help.appserver_3.1.400.v20090429_1800.jar

en mi shell bash (xubuntu10.04/xfce) realmente hace que el nombre de clase coincidente sea negrita ya que el fgrep resalta la cadena coincidente; esto hace que sea realmente fácil escanear la lista de cientos de archivos jar que se buscaron y ver fácilmente cualquier coincidencia.

en las ventanas puede hacer lo mismo con:

for /R %j in (*.jar) do @echo %j & @jar tf %j | findstr IObservableList 

nota que en ese ventanas en el separador de comando es '&' no ';' y que el '@' suprime el eco del comando para dar una salida ordenada como la salida de Linux de encontrar arriba; aunque findstr no hace que la cadena coincida sea negrita, debe acercarse un poco más a la salida para ver el nombre de la clase coincidente. Resulta que las ventanas 'para' comando sabe bastantes trucos como bucle a través de archivos de texto ...

disfrutan

Cuestiones relacionadas