Estoy intentando ejecutar el siguiente comando:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar "{}" + 

Esto devuelve un error:

find: missing argument to -exec 

No puedo «ver qué» está mal con este comando, ya que parece coincidir con la página del manual :

-exec command {} +

Esta variante de la opción -exec 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. La línea de comando se construye de la misma manera que xargs construye su líneas de comando. Solo se permite una instancia de «{}» dentro del comando. El comando se ejecuta en el directorio de inicio.

También probé:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar {} + find a/folder b/folder -name *.c -o -name *.h -exec "grep -I foobar" {} + find a/folder b/folder -name *.c -o -name *.h -exec "grep -I foobar" "{}" + find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar "{}" + find a/folder b/folder \( -name *.c -o -name *.h \) -exec grep -I foobar "{}" + find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar "{}" \+ 

Comentarios

  • ¿Ha intentado escapar del + al final? find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
  • Es posible que esté utilizando una versión anterior de GNU find. Aunque la variante -exec cmd {} + es POSIX y ha estado disponible desde los años 80, GNU find solo la agregó (relativamente) recientemente (2005). ¿Qué te dice find --version?
  • @Koveras, eso sería todo entonces. -exec {} + se agregó en 4.2.12 en 2005. En hallazgos de GNU más antiguos, puede usar el -print0 | xargs -r0 (no POSIX) para obtener algo similar. 4.1 es de 1994.
  • JRFerguson señaló (en una respuesta que ha sido eliminada) que el patrón -name los argumentos se deben citar: -name "*.c" -o -name "*.h". Esto es cierto, aunque no está relacionado con el error -exec. Notará que todas las demás respuestas ponen los comodines entre comillas, aunque solo Gilles lo menciona. … (Continuación)
  • (Continuación) … la respuesta de jlliagre contrae la expresión del nombre a -name "*.[ch]" sin explicación. Esto tiene los beneficios de simplificar la línea de comandos y, específicamente, eliminar el -o. Encontrar expresiones que incluyan -o son difíciles de acertar. El tuyo está mal; si su comando está arreglado para que no genere errores (como en la respuesta de Gilles), se ejecutará grep solo en .h archivos. Debe hacer '(' -name '*.c' -o -name '*.h' ')'.

Responder

Hubo varios problemas con sus intentos, incluido el uso de comillas invertidas en lugar de comillas (eliminadas en ediciones posteriores de la pregunta), comillas faltantes donde son necesarias, comillas adicionales donde son inútiles, paréntesis faltantes para el grupo -o cláusulas y diferentes implementaciones de find utilizadas (consulte los comentarios y el chat para obtener más detalles).

De todos modos, el comando se puede simplificar así:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} + 

o, si usa una versión arcaica de búsqueda de GNU, esto siempre debería funcionar:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} \; 

Comentarios

  • Vaya, estaban destinados a ser comillas, no comillas.
  • Las citas serían inútiles como {} no tiene un significado específico para el shell.
  • De las páginas de manual de búsqueda: » La cadena ‘ { } ‘ es reemplazado por el nombre del archivo actual que se procesa en todos los lugares en los que aparece en los argumentos del comando, no solo en los argumentos en los que está solo, como en algunas versiones de find. Es posible que sea necesario escapar de estas dos construcciones (con un ‘ \ ‘) o entre comillas para protegerlas de la expansión del shell. »
  • De hecho, leí eso en la página del manual, pero el hecho es que no hay un shell que ‘ sepa eso requiere citar las llaves. ¿Qué shell estás usando?
  • bash. Con o sin las comillas, obtengo el error de todos modos.

Respuesta

“argumento faltante para -exec ”normalmente significa que al argumento de – exec le falta su terminador. El terminador debe ser un argumento que contenga solo el carácter ; (que debe estar entre comillas en un comando de shell, por lo que normalmente se escribe \; o ";"), o dos argumentos sucesivos que contengan {} y +.

Stephane Chazelas ha identificado que estás usando una versión anterior de GNU find que no es compatible con -exec … {} +, solo -exec {} \;.Aunque GNU adoptó tardíamente -exec … {} +, le recomiendo que obtenga un conjunto de herramientas menos antiguo (como Cygwin , que incluye git y mucho más, o GNUwin32 , que carece de git pero no tiene el bad-employee-tratando-de-usar-linux -pero-impongamos-la vibración de Windows que da Cygwin). Esta característica se agregó en la versión 4.2.12, hace más de 9 años (fue la última característica identificada para hacer que GNU find Compatible con POSIX).

Si desea ceñirse a una búsqueda GNU anterior, puede usar -print0 con xargs -0 para obtener una funcionalidad similar: ejecución de comandos agrupados, que admite nombres de archivos arbitrarios.

find a/folder b/folder -name "*.c" -o -name "*.h" -print0 | xargs -0 grep -I foobar /dev/null 

Siempre cite los comodines en find línea de comando. De lo contrario, si ejecuta este comando desde un directorio que contiene .c archivos, el *.c sin comillas d se expandirá a la lista de .c archivos en el directorio actual.

Añadiendo /dev/null al grep la línea de comandos es un truco para garantizar que grep siempre imprima el nombre del archivo, incluso si find encuentra una única coincidencia. Con GNU find, otro método es pasar la opción -H.

Comentarios

  • ¿Qué ¿Quiere decir con mal empleado tratando de usar linux pero imponiendo ventanas que cygwin da?
  • GNUwin32 no ‘ no tiene expectativas 🙁
  • Vea mi (s) comentario (s) sobre la pregunta.
  • Las comillas alrededor del semi trabajaron desde un script package.json.

Responder

Si un comando como

find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar {} + 

devuelve un error

find: missing argument to -exec 

la causa probable es GNU find demasiado antiguo que no admite la sintaxis -exec mycommand {} +. En ese caso, el reemplazo de bajo rendimiento es ejecutar -exec mycommand {} \;, que ejecutará mycommand una vez por cada objetivo encontrado en lugar de recopilar varios objetivos y ejecutando mycommand solo una vez.

Sin embargo, GNU find doe s no es compatible, por ejemplo,

find . -type f -and -name "*.ttf" -exec cp {} ~/.fonts + 

porque GNU find solo admite la combinación literal {} + en lugar de {} additional parameters + más genéricos. Tenga en cuenta que no puede haber nada entre las llaves y el carácter +. Si intenta esto, obtendrá el mismo error:

find: missing argument to -exec 

La solución es utilizar la sintaxis {} additional parameters \; que funciona pero ejecutará el comando una vez por cada objetivo encontrado. Si necesita más rendimiento con GNU find, debe escribir un script de envoltura que pueda agregar parámetros adicionales a los argumentos dados. Algo como

 #!/bin/bash exec mycommand "$@" additional parameters  

debería ser suficientemente bueno. O, si no desea crear un archivo temporal, puede usar una sola línea para cambiar el orden de los parámetros como este:

find . -type f -and -name "*.ttf" -exec bash -c "mycommand "$@" extra arguments" {} + 

que ejecutará mycommand {list of ttf files} extra arguments. Tenga en cuenta que es posible que deba aplicar doble escape a los caracteres especiales para el bash después de la marca -c.

Comentarios

  • (1) La parte de lo anterior que realmente responde a la pregunta ya fue dada por otras personas. (2) Lo que está describiendo no es una falla o deficiencia en GNU find, sino el comportamiento correcto especificado por POSIX .
  • +1 Finalmente, alguien que responda por qué los parámetros adicionales ‘ no funcionan. Parece una deficiencia en la definición de POSIX.
  • Si ‘ ve GNU find usted ‘ probablemente tenga GNU cp. En este caso, podría find ... -exec cp --target-directory ~/.fonts {} + para mantener el {} al final de la cadena de ejecución.

Respuesta

find . -type f -perm 0777 -exec chmod 644 {}\;

Obtuve el error find: missing argument to ``-exec".

Agregar espacio entre {} y \ lo solucionó:

find . -type f -perm 0777 -print -exec chmod 644 {} \;

Comentarios

  • No existe tal problema en el find comando en la pregunta en cuestión.
  • En Pregunta no es, bien, lo que entendí, pero el problema es el mismo » buscar: argumento faltante a « -exec ‘ «, el problema puede ocurrir por una razón diferente-2, respondí porque vi la misma declaración de problema.
  • @Kusalananda, Dios mío, el novato brindó una solución para el error informado que el OP indica tanto en el título como en el cuerpo de la pregunta.
  • @bvj La pregunta trata explícitamente con la forma + de la opción -exec a find. Esta respuesta corrige un problema que el usuario que hace la pregunta no tiene.

Respuesta

Tenía mi cuota de dolores de cabeza con la sintaxis ejecutiva en el pasado. la mayoría de los días ahora prefiero la sintaxis de bash más agradable:

for f in `find a/folder b/folder -name "*.[ch]"`; do grep -I foobar $f; done 

Tiene algunas limitaciones cuando desea tratar los archivos como un grupo, ya que cada uno se evalúa en serie, pero puede canalizar la salida a otra parte sin problemas

Comentarios

  • Si bien esto tiende a funcionar, es significativamente menos útil que la versión de búsqueda pura porque no puede manejar archivos con espacios en blanco en el nombre correctamente.
  • No, no ‘ no haga esto. Esto se rompe tan pronto como los archivos contienen espacios y otros caracteres «extraños». Esto también es más complejo y más lento que find … -exec … \;, por lo que ‘ no hay razón para usarlo incluso si sabe que los nombres de sus archivos son tame.
  • esto fue útil para mi situación en la que necesitaba ejecutar varias líneas de lógica en función de los nombres de los archivos (como eliminar caracteres, crear directorios y luego mover los archivos). Intentar conseguir que find hiciera varias cosas en una exec fue un dolor de cabeza para los 5 minutos que quería dedicarle a esto. Mis nombres de archivo eran mansos y esto resolvió mi problema 🙂

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *