¿Cómo puedo hacer que la búsqueda falle si -exec falla?

23

Cuando ejecuto este comando en el shell (en un directorio no vacío):

find . -exec invalid_command_here {} \;

Me sale esto:

find: invalid_command_here: No such file or directory
find: invalid_command_here: No such file or directory
find: invalid_command_here: No such file or directory

(y así sucesivamente para cada archivo)

Necesito que find falle después del primer error. ¿Hay alguna manera de hacer que esto funcione? No puedo usar xargs , ya que tengo espacios en mi ruta, pero necesito que el script llame a este para devolver un código de error.

    
pregunta Steven Fisher 18.04.2012 - 22:10

3 respuestas

28

Esta es una limitación de find . El POSIX standard especifica que el estado de devolución de find es 0, a menos que se produzca un error al atravesar los directorios el estado de retorno de los comandos ejecutados no entra en él.

Puede hacer que los comandos escriban su estado en un archivo o en un descriptor:

find_status_file=$(mktemp findstatus)
: >"$find_status_file"
find … -exec sh -c 'trap "echo \$?" EXIT; invalid_command "$0"' {} \;
if [ -s "$find_status_file" ]; then
  echo 1>&2 "An error occurred"
fi
rm -f "$find_status_file"

Otro método, a medida que descubierto , es utilizar xargs. Los comandos xargs siempre procesan todos los archivos, pero devuelven el estado 1 si alguno de los comandos devuelve un estado distinto de cero.

find … -print0 | xargs -0 -n1 invalid_command

Otro método más es evitar find y, en su lugar, utilizar globos recursivos en el shell: **/ significa cualquier profundidad de subdirectorios. Esto requiere la versión 4 o superior de bash; macOS está bloqueado en la versión 3.x, por lo que tendría que instalarlo desde una colección de puertos. Utilice set -e para detener la secuencia de comandos en el primer comando que devuelve un estado distinto de cero.

shopt -s globstar
set -e
for x in **/*.xml; do invalid_command "$x"; done

Tenga en cuenta que en bash 4.0 a 4.2, esto funciona pero atraviesa enlaces simbólicos a directorios, lo que generalmente no es deseable.

Si usas zsh en lugar de bash, los globos recursivos funcionan fuera de la caja sin errores. Zsh está disponible por defecto en OSX / macOS. En zsh, solo puedes escribir

set -e
for x in **/*.xml; do invalid_command "$x"; done
    
respondido por el Gilles 20.04.2012 - 02:34
18

Puedo usar esto en su lugar:

find . -name *.xml -print0 | xargs -n 1 -0 invalid_command
    
respondido por el Steven Fisher 18.04.2012 - 22:21
1

xargs es una opción. Sin embargo, es realmente fácil hacerlo con find y usando + en lugar de \; :

-exec  utility_name  [argument ...]   {} +

De la documentación de POSIX :

  

Si la expresión primaria está puntuada por un signo más, la primaria siempre se evaluará como verdadera, y las rutas para las cuales se evalúa la primaria se agregarán en conjuntos. La utilidad utility_name se invocará una vez para cada conjunto de rutas agregadas. Cada invocación comenzará después de que se agregue el último nombre de ruta en el conjunto, y se completará antes de que salga la utilidad de búsqueda y antes de que se agregue el primer nombre de ruta en el siguiente conjunto (si existe) para este primario, pero no se especifica de otro modo si la invocación ocurre antes, durante o después de las evaluaciones de otras primarias. Si cualquier invocación devuelve un valor distinto de cero como estado de salida, la utilidad de búsqueda devolverá un estado de salida distinto de cero. Un argumento que contenga solo los dos caracteres "{}" se reemplazará por el conjunto de Las rutas de acceso agregadas, con cada ruta de acceso pasada como un argumento separado a la utilidad invocada en el mismo orden en que se agregaron. El tamaño de cualquier conjunto de dos o más rutas de acceso se limitará de modo que la ejecución de la utilidad no haga que se exceda el límite {ARG_MAX} del sistema. Si hay más de un argumento que contiene solo los dos caracteres "{}", el comportamiento no está especificado.

    
respondido por el Swiss 28.09.2018 - 21:18

Lea otras preguntas en las etiquetas