Tengo un script bash que utiliza set -o errexit
para que, en caso de error, todo el script salga en el punto de falla.
El script ejecuta un curl
comando que a veces no puede recuperar el archivo deseado; sin embargo, cuando esto ocurre, el script no sale por error.
He agregado un for
bucle a
- pausa por unos segundos y luego vuelve a intentar el
curl
comando - use
false
en la parte inferior del bucle for para definir un estado de salida predeterminado distinto de cero, si el comando curl tiene éxito, el bucle se rompe y el estado de salida del último comando debería ser cero.
#! /bin/bash
set -o errexit
# ...
for (( i=1; i<5; i++ ))
do
echo "attempt number: "$i
curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
if [ -f ~/.vim/autoload/pathogen.vim ]
then
echo "file has been retrieved by curl, so breaking now..."
break;
fi
echo "curl'ed file doesn't yet exist, so now will wait 5 seconds and retry"
sleep 5
# exit with non-zero status so main script will errexit
false
done
# rest of script .....
El problema es cuando el curl
comando falla, el ciclo vuelve a intentarlo cinco veces, si todos los intentos no tienen éxito, el ciclo for finaliza y se reanuda el script principal, en lugar de activar el errexit
.
¿Cómo puedo hacer que salga el script completo si esta curl
declaración falla?
fuente
true
antes de la declaración de ruptura para ser explícito y garantizar el valor de salida del bucle?exit 1
cuando simplementeexit
hubiera funcionado. Sin embargo, es una cuestión de estilo y otros pueden tener sus propias opiniones.exit
como una salida simple, que termina el script por derecho propio.exit 1
me leería como una "señal" a algún otro proceso (es decirerrexit
), que debería terminar el script en función del "resultado" deexit 1
. - así que he idoexit
pero gracias por la explicaciónexit 1
. Eso no afectaerrexit
en absoluto. Simplemente le dice al programa de llamadas que algo salió mal. Elfalse
comando contiene una declaración:exit(1)
. El 99.9% de los comandos de Unix devuelven 0 en caso de éxito y no cero en caso de error. El tuyo también debería.Si lo ha
errexit
configurado, lafalse
declaración debería hacer que el script salga inmediatamente. Lo mismo si elcurl
comando falla.Su script de ejemplo, tal como está escrito, debería salir después del primer
curl
fallo del comando la primera vez que llamafalse
si se establece errexit.Para ver cómo funciona (uso la abreviatura
-e
para configurarerrexit
:Entonces, si el
curl
comando se ejecuta más de una vez, este script no se haerrexit
configurado.fuente
set -e
Es más sutil que eso. Será no salir después del comando primera fallado en un bucle. Puede probarlo usted mismo al ejecutar(set -e; for (( i=1; i<5; i++ )); do echo $i; false; done || echo "FAIL"; )
y observar que el código se ejecutafalse
cuatro veces. Para más informaciónset -e
, consulte las preguntas frecuentes de Greg # 105 .errexit
no se estableció. Aplique la lógica al script en la pregunta. Ejecute esto:(set -e; for (( i=1; i<5; i++ )); do echo $i; false; done ; echo still here )
Sí, probar los valores de retorno conif
while
||
&&
etc. no activa errexit. El guión original no incluía||
el bucle for.set -o errexit
comando en mi código de ejemplo, lo he agregado ahora, y para mí no fue un error al salir como se esperaba. Necesitaba mantener elfalse
como el último comando en el bucle for, luego cerrar el bucle condone || exit [1]
- ¡entonces funcionó bien!set -o errexit
puede ser complicado en bucles y subcapas, porque tienes que volver a salir del proceso.Romper un bucle (incluso en funcionamiento normal) se considera una mala práctica. Puedes llamarme de la vieja escuela para preferir un ciclo while en lugar de un ciclo for por dos condiciones, pero me parece mejor leerlo:
fuente
Si
errexit
está configurado y elcurl
comando falla, el script termina justo después del comando curl fallido. En el manual de bash no hay ninguna pista queset -e
ignore cualquier estado de retorno fallido de un solo comando compuesto. Este sería solo el caso si el comando compuesto se ejecuta en un contexto dondeset -e
se ignora.https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin
Pruebe un ejemplo ligeramente adaptado publicado por RobertL. Esto se detiene en la primera iteración justo después del comando falso:
fuente
Simplemente puede agregar la opción --fail al comando curl, esto resolverá su problema, el script fallará y saldrá por error si el comando curl falla, si es muy útil también cuando se usa curl en la tubería jenkins:
fuente