Comprender la opción -exec de find (1) (llaves y signo más)

17

Usando el siguiente comando, ¿podría alguien explicar cuál es exactamente el propósito de las llaves ({}) y el signo más (+)?

¿Y cómo funcionaría el comando de manera diferente si fueran excluidos del comando?

find . -type d -exec chmod 775 {} +
Ryan Prentiss
fuente

Respuestas:

19

Las llaves se reemplazarán por los resultados del findcomando y chmodse ejecutarán en cada una de ellas. Las +marcas findintentan ejecutar comandos como pocos como sea posible (por lo que, chmod 775 file1 file2 file3a diferencia de chmod 755 file1, chmod 755 file2, chmod 755 file3). Sin ellos, el orden de la misma da un error. Todo esto se explica en man find:

-exec command ;

      Ejecutar comando ; verdadero si se devuelve el estado 0. Todos los siguientes argumentos findse consideran argumentos del comando hasta que se encuentre un argumento que consista en ' ;'. La cadena ' {}' se sustituye por el nombre del archivo actual está procesando todas partes se produce en los argumentos para el comando, no sólo en los argumentos en los que está solo, ya que en algunas versiones de find. ...

-exec command {} +

      Esta variante de la -execacción ejecuta el comando especificado en los archivos seleccionados, pero la línea de comando se construye agregando cada nombre de archivo seleccionado al final; El número total de invocaciones del comando será mucho menor que el número de archivos coincidentes. ...

terdon
fuente
12

Además de la respuesta de terdon,

  • “Obviamente” -exec …debe terminar con un punto y coma bien ( ;) o un signo más ( +). Punto y coma es un carácter especial en el shell (o, al menos, todos los depósitos que he usado), por lo que, si se va a utilizar como parte del findcomando , que debe ser escapado o citado ( \;, ";"o ';').
  • Con -exec … ;, la {}cadena puede aparecer cualquier número de veces en el comando, incluido cero , o dos o más, en cualquier posición.  Ver este un ejemplo de por qué es posible que desee hacerlo -execsin utilizar {}.   Tener dos o más apariencias es útil principalmente porque, en (al menos) algunas versiones de find, el {}no necesita ser una palabra en sí misma; puede tener otros personajes al principio o al final; p.ej,

    find . -type f -exec mv {} {}.bak ";"
    

    Con -exec … +, la {}cadena debe aparecer como el último argumento ante el +. Un comando como

    find . -name "*.bak" -exec mv {} backup_folder +
    

    da como resultado el enigmático find: missing argument to ‘-exec’mensaje de error.

    • Una solución para este que es específico para el cpy mvcomandos es

      find . -name "*.bak" -exec mv -t backup_folder {} +
      

      o

      find . -name "*.bak" -exec mv --target-directory=backup_folder {} +
      

    El {}debe ser una palabra por sí misma; no puede tener otros personajes al principio o al final. Y, en (al menos) algunas versiones de find, no puede tener más de una {}.

  • Una nota de cordura: Usted puede decir

    encontrar . -name "* .sh" type f -executable -exec {} argumentos opcionales aquí ";"

    para ejecutar cada una de las secuencias de comandos. Pero

    encontrar . -name "* .sh" -tipo f -executable -exec {} +

    ejecuta uno de sus scripts, con los nombres de todos los demás como parámetros. Esto es similar a decir

    ./*.sh
    

    como un comando de shell, excepto findque no garantiza que clasifique sus resultados, por lo que no se garantiza que se ejecute aaa.sh (su primer *.sharchivo alfabéticamente ) como lo estaría con la ejecución ./*.sh.

  • Un aspecto de findeso puede no estar perfectamente claro para los principiantes es que la línea de comando es, efectivamente, una declaración ejecutable en un lenguaje arcano. Por ejemplo,

    find . -name "*.sh" -type f -executable -print
    

    medio

    for each file
        if the file’s name matches `*.sh` (i.e., if it ends with `.sh`)
        then
            if it is a plain file (i.e., not a directory)
            then
                if it is executable (i.e., the appropriate `---x--x--x` bit is set)
                then
                    print the file’s name
                end if
            end if
        end if
    end loop
    

    o simplemente,

    for each file
        if the file’s name matches `*.sh`  AND  it is a plain file  AND  it is executable
        then
            print the file’s name
        end if
    end loop
    

    Algunas de las -palabras clave son tanto una acción ejecutable como una prueba. En particular, esto es cierto para -exec … ;; por ejemplo,

    find . -type f -exec grep -q cat {} ";" -print
    

    se traduce en

    para cada archivo
        si es un archivo simple (es decir, no un directorio)
        luego
            ejecutar grep -q gato de nombre de archivo
            si el proceso tiene éxito (es decir, sale con el estado 0)
            luego
                imprimir el nombre del archivo
            terminara si
        terminara si
    bucle final

    que imprimirá los nombres de todos los archivos que contienen la cadena “ cat”. Y, si bien esto es algo que greppuede hacer por sí mismo (con la opción -l(en minúsculas L)), puede ser útil usarlo findpara buscar archivos que contengan una determinada cadena Y tengan un cierto tamaño Y sean propiedad de un determinado propietario Y fueron modificados en un cierto rango de tiempo, ...

    Sin embargo, esto no funciona -exec … +. Dado que -exec … +ejecuta un comando para varios archivos, no tiene sentido usarlo como una condición lógica dentro de un for each file …bucle.

  • La otra cara de lo anterior es que findgeneralmente sale con un estado de salida de 0 a menos que le des argumentos inválidos o encuentre un directorio que no puede leer. Incluso si un programa que ejecuta falla (sale con un estado de salida distinto de cero), findsaldrá con un estado de salida de 0.  Excepto  si un programa que ejecuta con -exec … +falla (sale con un estado de salida distinto de cero), findsaldrá con un estado de salida distinto de cero.

Además de un millón de versiones find(1) y pruebas de lo que findrealmente hace en un par de sistemas, el número 7 de la edición de especificaciones de Open Group Base, 2013 proporcionó información sobre lo que finddebe, puede y no debe hacer.

G-Man dice 'restablecer a Monica'
fuente
3
Tenga en cuenta que su ejemplo usando ... -exec mv {} {}.bak ...no es garantizado al trabajo como se esperaba con todas las findimplementaciones. Los estados estándar POSIX {}deben aparecer solos para ser siempre reconocidos, de lo contrario el comportamiento es libre de mantener los caracteres sin cambios o reemplazarlos por el nombre de ruta. En el primer caso, todo su comando esencialmente eliminará todos los archivos, pero el último encontrado ...
jlliagre