Tengo un script bash que utiliza set -o errexitpara que, en caso de error, todo el script salga en el punto de falla.
El script ejecuta un curlcomando que a veces no puede recuperar el archivo deseado; sin embargo, cuando esto ocurre, el script no sale por error.
He agregado un forbucle a
- pausa por unos segundos y luego vuelve a intentar el
curlcomando - use
falseen 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 curlcomando 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 curldeclaración falla?
fuente

trueantes de la declaración de ruptura para ser explícito y garantizar el valor de salida del bucle?exit 1cuando simplementeexithubiera funcionado. Sin embargo, es una cuestión de estilo y otros pueden tener sus propias opiniones.exitcomo una salida simple, que termina el script por derecho propio.exit 1me 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 idoexitpero gracias por la explicaciónexit 1. Eso no afectaerrexiten absoluto. Simplemente le dice al programa de llamadas que algo salió mal. Elfalsecomando 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
errexitconfigurado, lafalsedeclaración debería hacer que el script salga inmediatamente. Lo mismo si elcurlcomando falla.Su script de ejemplo, tal como está escrito, debería salir después del primer
curlfallo del comando la primera vez que llamafalsesi se establece errexit.Para ver cómo funciona (uso la abreviatura
-epara configurarerrexit:Entonces, si el
curlcomando se ejecuta más de una vez, este script no se haerrexitconfigurado.fuente
set -eEs 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 ejecutafalsecuatro veces. Para más informaciónset -e, consulte las preguntas frecuentes de Greg # 105 .errexitno 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 conifwhile||&&etc. no activa errexit. El guión original no incluía||el bucle for.set -o errexitcomando en mi código de ejemplo, lo he agregado ahora, y para mí no fue un error al salir como se esperaba. Necesitaba mantener elfalsecomo el último comando en el bucle for, luego cerrar el bucle condone || exit [1]- ¡entonces funcionó bien!set -o errexitpuede 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
errexitestá configurado y elcurlcomando falla, el script termina justo después del comando curl fallido. En el manual de bash no hay ninguna pista queset -eignore 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 -ese 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