¿Cómo utilizo una tubería en el parámetro exec para un comando de búsqueda?

77

Estoy tratando de construir un comando de búsqueda para procesar un montón de archivos en un directorio usando dos ejecutables diferentes. Desafortunadamente, -execon find no permite usar pipe o incluso \|porque el shell interpreta ese carácter primero.

Esto es específicamente lo que estoy tratando de hacer (que no funciona porque la tubería finaliza el comando de búsqueda):

find /path/to/jpgs -type f -exec jhead -v {} | grep 123 \; -print
hoyhoy
fuente

Respuestas:

87

Prueba esto

find /path/to/jpgs -type f -exec sh -c 'jhead -v {} | grep 123' \; -print

Alternativamente, puede intentar incrustar su declaración ejecutiva dentro de un script sh y luego hacer:

find -exec some_script {} \;
Martín Marconcini
fuente
15

Un enfoque ligeramente diferente sería usar xargs:

find /path/to/jpgs -type f -print0 | xargs -0 jhead -v | grep 123

que siempre encontré un poco más fácil de entender y adaptar (los argumentos -print0 y -0 son necesarios para hacer frente a los nombres de archivo que contienen espacios en blanco)

Esto podría (no probado) ser más efectivo que usar -exec porque canalizará la lista de archivos a xargs y xargs se asegura de que la línea de comandos jhead no sea demasiado larga.

Palmin
fuente
4
El problema con el uso de xargs aquí es que necesito el nombre del archivo que coincide. Este comando encuentra las coincidencias, pero no sé qué archivo coincide.
hoyhoy
4

Con -execsolo puede ejecutar un único ejecutable con algunos argumentos, no comandos de shell arbitrarios. Para evitar esto, puede usar sh -c '<shell command>'.

Tenga en cuenta que el uso de -execes bastante ineficiente. Para cada archivo que se encuentre, el comando debe ejecutarse nuevamente. Sería más eficaz si pudiera evitarlo. (Por ejemplo, moviendo el grepfuera de la -execo las tuberías de los resultados de finda xargscomo se sugiere por Palmin .)

mweerden
fuente
1
Otra forma de evitar la ineficiencia de múltiples procesos en el caso general es usar xargs. Si necesita procesos separados, puede usar la opción -i. Encuentro xargs más acorde con el modelo Unix.
Jon Ericson
1
AOL en el uso de xargs. mweerden, tal vez debería cambiar su último párrafo teniendo en cuenta la existencia de xargs. También tenga en cuenta la bandera -0 que existe en ambos findy xargs.
tzot
3

Utilizando find comando para este tipo de tarea quizás no sea la mejor alternativa. Utilizo el siguiente comando con frecuencia para encontrar archivos que contienen la información solicitada:

for i in dist/*.jar; do echo ">> $i"; jar -tf "$i" | grep BeanException; done
Dimitar
fuente
1

Como esto genera una lista, ¿no:

find /path/to/jpgs -type f -exec jhead -v {} \; | grep 123

o

find /path/to/jpgs -type f -print -exec jhead -v {} \; | grep 123

Ponga su grep en los resultados de la búsqueda -exec.

Xetius
fuente
Eso no funciona porque necesito la impresión para que funcione. Si grep devuelve un éxito, find imprime el nombre del archivo, de lo contrario no lo hace.
hoyhoy
0

Hay otra forma de hacerlo, pero también es bastante gueto.

Usando la opción de shell extquote, puede hacer algo similar a esto para encontrar cosas ejecutivas y luego canalizarlas a sh.

root@ifrit findtest # find -type f -exec echo ls $"|" cat \;|sh
filename


root@ifrit findtest # find -type f -exec echo ls $"|" cat $"|" xargs cat\;|sh
h

Pensé que lo agregaría porque al menos de la forma en que lo visualicé, estaba más cerca de la pregunta original del OP de usar tuberías dentro de exec.

linuxgeek
fuente