¿Cómo funciona este comando de búsqueda utilizando "find ... -exec sh -c '...' sh {} +"?

8

@StephaneChazelas publicó la siguiente solución a estas preguntas y respuestas: Tiene problemas para usar "find -exec {} +" .

$ find . -iname "*.extension" -exec sh -c '
  exec <command> "$@" <additional parameters>' sh {} +

Qué está pasando aquí? Específicamente, ¿qué hace el último sh {}? Parece que solo está ahí para pacificar el -execcomando de find para que tenga algo que hacer, un NOOP.

Podría ponerlo fácilmente echo {}y parece funcionar bien.

slm
fuente

Respuestas:

9

La sintaxis es:

find ... -exec cmd {} +

findencontrará una cantidad de archivos basados ​​en los criterios ...y se ejecutará cmdcon esa lista de rutas de archivo como argumentos, tantos como sea posible sin superar el límite del tamaño de los argumentos de un comando.

Si es necesario, puede dividir la lista de archivos y llamar cmdvarias veces. Por ejemplo, puede terminar llamando:

cmd ./file1 ./file2 ... ./file3000
cmd ./file3001 ./file3002 ... ./file4321

Una limitación con eso es que {}tiene que ser la última. No puedes por ejemplo escribir:

find ... -exec cmd {} other args +

como podrías con en ';'lugar de '+'.

Puedes escribir:

find ... -exec echo foo {} +

pero no:

find ... -exec echo {} foo +

Entonces, si necesita agregar algunos argumentos adicionales cmddespués de la lista de archivos, debe recurrir a llamar a un shell. (Otras razones por las que necesitaría llamar a un shell serían cada vez que necesite usar una función de shell como redirecciones, tuberías, algunas expansiones de cadenas ...)

En sh -c 'inline-script' x a b c, para inline-script, $0es x, $1es a, $2es b... también lo "$@"es la lista de esos 3 argumentos: a, by c. Entonces en:

find ... -exec sh -c 'cmd "$@" other arg' find-sh {} +

Para la secuencia de comandos en línea , $0(que se utiliza, por ejemplo, cuando se muestran mensajes de error) se establece en find-shy "$@"es la lista de archivos (a lo que se findexpande {}).

Mediante el uso de la execconstrucción especial de la carcasa:

find ... -exec sh -c 'exec cmd "$@" other arg' find-sh {} +

Le decimos al shell que no bifurque un proceso adicional para ejecutar cmd, sino que lo ejecute en el mismo proceso (reemplazando el proceso de ejecución del shell con ese comando). A algunos shells les gusta bash, zshy algunas implementaciones de kshhacer eso implícitamente para el último comando en un script.

Stéphane Chazelas
fuente
¿Podría usar una subshell en lugar de exec allí? -exec sh -c '(cmd1; cmd2;)' find-sh {} +?
slm
Entonces, si te entiendo correctamente, find-sh {}hay argumentos para el comando sh -c '...', ¿verdad?
slm
@slm, findllamará /bin/shcon argumentos como ("sh", "-c", "...", "find-sh", "./file1", "./file2"...). And inside ... , that maps (the shells maps that) to $ 0` ser "find-sh", y los parámetros de posición ( $1, $2... lo que se podría decir que son los argumentos de la secuencia de comandos en línea ) siendo ./file1, ./file2.
Stéphane Chazelas