Me encuentro constantemente buscando la sintaxis de
find . -name "FILENAME"  -exec rm {} \;principalmente porque no veo exactamente cómo funciona la -execpieza. ¿Cuál es el significado de las llaves, la barra diagonal inversa y el punto y coma? ¿Hay otros casos de uso para esa sintaxis?

manpágina POSIX anterior dice: Un nombre de utilidad o argumento que contiene solo los dos caracteres "{}" se reemplazará por el nombre de ruta actual , que me parece suficiente. Además, tiene un ejemplo con-exec rm {} \;, al igual que en su pregunta. En mis días, apenas había otros recursos que la "gran pared gris", libros demanpáginas impresas (el papel era más barato que el almacenamiento). Entonces sé que esto es suficiente para alguien nuevo en el tema. Sin embargo, su última pregunta es justa de hacer aquí. Desafortunadamente ni @Kusalananda ni yo tenemos una respuesta a eso.xargsveces es útil,findpuede pasar múltiples argumentos de ruta al comando sin él.-exec command... {} +(con en+lugar de\;) pasa tantas rutas despuéscommand...como quepan (cada sistema operativo tiene su propio límite en cuanto a la longitud de una línea de comandos). Y al igual quexargs, la+forma terminada en defind's-execacción también se ejecutarácommand...varias veces en el caso raro de que hay demasiados caminos para ajustarse al límite.Respuestas:
Esta respuesta viene en las siguientes partes:
-exec-execen combinación consh -c-exec ... {} +-execdirUso básico de
-execLa
-execopción toma una utilidad externa con argumentos opcionales como argumento y la ejecuta.Si la cadena
{}está presente en cualquier parte del comando dado, cada instancia de la misma será reemplazada por el nombre de ruta que se está procesando actualmente (por ejemplo./some/path/FILENAME). En la mayoría de los shells,{}no es necesario citar los dos caracteres .El comando debe terminarse con un
;parafindsaber dónde termina (ya que puede haber más opciones después). Para protegerlo;del shell, debe citarse como\;o';', de lo contrario, el shell lo verá como el final delfindcomando.Ejemplo (
\al final de las dos primeras líneas son solo para continuar con las líneas):Esto encontrará todos los archivos normales (
-type f) cuyos nombres coincidan con el patrón*.txten o debajo del directorio actual. Luego probará si la cadena sehelloproduce en alguno de los archivos encontradosgrep -q(lo que no produce ningún resultado, solo un estado de salida). Para aquellos archivos que contienen la cadena,catse ejecutará para enviar el contenido del archivo al terminal.Cada uno
-exectambién actúa como una "prueba" en los nombres de ruta encontrados porfind, al igual que-typey lo-namehace. Si el comando devuelve un estado de salida cero (que significa "éxito"), se considera la siguiente parte delfindcomando; de lo contrario, elfindcomando continúa con el siguiente nombre de ruta. Esto se usa en el ejemplo anterior para buscar archivos que contienen la cadenahello, pero para ignorar todos los demás archivos.El ejemplo anterior ilustra los dos casos de uso más comunes de
-exec:findcomando).Utilizando
-execen combinación consh -cEl comando que
-execpuede ejecutarse está limitado a una utilidad externa con argumentos opcionales.-execNo es posible utilizar las funciones integradas de shell, funciones, condicionales, canalizaciones, redirecciones, etc. directamente , a menos que esté envuelto en algo así como unsh -cshell secundario.Si
bashse requieren funciones, úselasbash -cen lugar desh -c.sh -cse ejecuta/bin/shcon un script dado en la línea de comando, seguido de argumentos opcionales de la línea de comando para ese script.Un ejemplo simple de uso
sh -cpor sí mismo, sinfind:Esto pasa dos argumentos al script de shell hijo:
La cadena
sh. Estará disponible$0dentro del script, y si el shell interno genera un mensaje de error, lo colocará como prefijo con esta cadena.El argumento
applesestá disponible como$1en el script, y si hubiera habido más argumentos, entonces estos hubieran estado disponibles como$2,$3etc. También estarían disponibles en la lista"$@"(excepto de los$0cuales no serían parte de"$@").Esto es útil en combinación con,
-execya que nos permite crear scripts arbitrariamente complejos que actúan sobre los nombres de ruta encontrados porfind.Ejemplo: busque todos los archivos normales que tengan un sufijo de nombre de archivo determinado y cambie ese sufijo de nombre de archivo a otro sufijo, donde los sufijos se mantienen en variables:
Dentro de la secuencia de comandos interna,
$1estaría la cadenatext,$2sería la cadenatxty$3sería cualquier ruta quefindhaya encontrado para nosotros. La expansión del parámetro${3%.$1}tomaría la ruta y eliminaría el sufijo.text.O, usando
dirname/basename:o, con variables agregadas en el script interno:
Tenga en cuenta que en esta última variación, las variables
fromytoen el shell hijo son distintas de las variables con los mismos nombres en el script externo.Lo anterior es la forma correcta de llamar a un script complejo arbitrario
-execconfind. Usandofinden un bucle comoes propenso a errores y poco elegante (opinión personal). Está dividiendo nombres de archivos en espacios en blanco, invocando el bloqueo de nombres de archivo, y también obliga al shell a expandir el resultado completo
findincluso antes de ejecutar la primera iteración del bucle.Ver también:
Utilizando
-exec ... {} +Al
;final puede ser reemplazado por+. Esto hacefindque se ejecute el comando dado con tantos argumentos (nombres de ruta encontrados) como sea posible en lugar de una vez para cada nombre de ruta encontrado. La cadena{}debe aparecer justo antes+de que esto funcione .Aquí,
findrecopilará los nombres de ruta resultantes y los ejecutarácaten tantos como sea posible a la vez.Del mismo modo aquí,
mvse ejecutará la menor cantidad de veces posible. Este último ejemplo requiere GNUmvde coreutils (que admite la-topción).El uso
-exec sh -c ... {} +también es una forma eficiente de recorrer un conjunto de nombres de ruta con un script arbitrariamente complejo.Lo básico es lo mismo que cuando se usa
-exec sh -c ... {} ';', pero el script ahora toma una lista de argumentos mucho más larga. Estos se pueden recorrer en bucle"$@"dentro del script.Nuestro ejemplo de la última sección que cambia los sufijos de nombre de archivo:
Utilizando
-execdirTambién existe
-execdir(implementado por la mayoría de lasfindvariantes, pero no es una opción estándar).Esto funciona como
-execla diferencia de que el comando de shell dado se ejecuta con el directorio del nombre de ruta encontrado como su directorio de trabajo actual y que{}contendrá el nombre de base del nombre de ruta encontrado sin su ruta (pero GNUfindseguirá prefijando el nombre de base con./BSD).findNo haré eso).Ejemplo:
Esto moverá cada
*.txtarchivo encontrado a undone-textssubdirectorio preexistente en el mismo directorio donde se encontró el archivo . El archivo también será renombrado añadiéndole el sufijo.done.Esto sería un poco más complicado de hacer,
-execya que tendríamos que obtener el nombre base del archivo encontrado{}para formar el nuevo nombre del archivo. También necesitamos el nombre del directorio de{}para localizar eldone-textsdirectorio correctamente.Con
-execdir, algunas cosas como estas se vuelven más fáciles.La operación correspondiente usando en
-execlugar de-execdirtendría que emplear un shell hijo:o,
fuente
-exectoma un programa y argumentos y lo ejecuta; algunos comandos de shell consisten solo en un programa y argumentos, pero muchos no. Un comando de shell puede incluir redirección y canalización;-execno puede (aunque todofindse puede redirigir). Un comando de shell puede usar,; && ifetc;-execno puede, aunque-a -opuede hacer algo. Un comando de shell puede ser un alias o una función de shell, o integrado;-execno puedo. Un comando de shell puede expandir vars;-execno puede (aunque la capa externa que ejecuta lafindlata). Un comando de shell puede sustituir de manera$(command)diferente cada vez;-execno puedo. ...-execno puede, aunquefindpuede iterar sobre los archivos de la misma manera que la mayoría de los globs, por lo que rara vez se desea.shmismo, que es capaz de hacer todas esas cosasfind -exec cmd arg \;no invoca un shell para interpretar una línea de comando de shell, se ejecutaexeclp("cmd", "arg")directamente, noexeclp("sh", "-c", "cmd arg")(para lo cual el shell terminaría haciendo el equivalente deexeclp("cmd", "arg")sicmdno estuviera integrado).findargumentos después-execy hasta;o+compensar el comando a ejecutar junto con sus argumentos, con cada instancia de un{}argumento reemplaza con el archivo actual (con;), y{}como último argumento antes+reemplazado con una lista de archivos como argumentos separados (en el{} +caso). IOW-exectoma varios argumentos, terminados en a;o{}+.