¿Cómo puedo hacer que este script salga con error según el resultado del bucle for?

¿Cómo puedo hacer que este script salga con error según el resultado del bucle for?

Tengo un script bash que se 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 añadido un forbucle a

  1. haga una pausa durante unos segundos y luego vuelva a intentar el curlcomando
  2. utilícelo 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 debe 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 que cuando el curlcomando falla, el bucle reintenta el comando cinco veces; si todos los intentos no tienen éxito, el bucle for finaliza y se reanuda el script principal, en lugar de activar el archivo errexit.
¿Cómo puedo hacer que se cierre todo el script si esta curldeclaración falla?

Respuesta1

Reemplazar:

done

con:

done || exit 1

Esto hará que el código salga si el forbucle sale con un código de salida distinto de cero.

Como curiosidad, la 1entrada exit 1no es necesaria. Un comando simple exitsaldría con el estado de salida del último comando ejecutado, que sería false(código=1) si falla la descarga. Si la descarga se realiza correctamente, el código de salida del bucle es el código de salida del echocomando. echonormalmente sale con código = 0, lo que indica éxito. En ese caso, ||no se activa y el exitcomando no se ejecuta.

Por último, tenga en cuenta que set -o errexitpuede estar lleno de sorpresas. Para una discusión de sus pros y contras, verPreguntas frecuentes #105 de Greg.

Documentación

De man bash:

para((expr1; expr2; expr3));hacerlista ; hecho
Primero, la expresión aritmética expr1 se evalúa de acuerdo con las reglas que se describen a continuación en EVALUACIÓN ARITMÉTICA. Luego, la expresión aritmética expr2 se evalúa repetidamente hasta que da como resultado cero. Cada vez que expr2 se evalúa como un valor distinto de cero, se ejecuta list y se evalúa la expresión aritmética expr3. Si se omite alguna expresión, se comporta como si su evaluación fuera 1. El valor de retorno es el estado de salida del último comando de la lista que se ejecuta, o falso si alguna de las expresiones no es válida.[Énfasis añadido]

Respuesta2

Si prefiere detener el ciclo en el primer fallo y también evitarlo set -e, puede hacer algo como esto:

for i in `seq 1 10`; do
  run_command || exit 1;
done

Respuesta3

Si lo ha errexitconfigurado, entonces la falsedeclaración debería hacer que el script se cierre inmediatamente. Lo mismo si el curlcomando falla.

Su script de ejemplo, tal como está escrito, debería salir después del primer curlerror del comando la primera vez que llama falsesi se establece errexit.

Para ver cómo funciona (uso la abreviatura -ede configurar errexit:

$ ( set -e;  false; echo still here )
$

$ ( set +e;  false; echo still here )
still here
$

Entonces, si el curlcomando se ejecuta más de una vez, este script no está errexitconfigurado.

Respuesta4

set -o errexitPuede ser complicado en bucles y subcapas, porque hay 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 bucle while en lugar de un bucle for para dos condiciones, pero me parece mejor leer:

i=1
RET=-1
while [ $i -le 5 ] && [ $RET -ne 0 ]; do
    [ $i -eq 1 ] || sleep 5
    echo "attempt number: "$i
    curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
    RET=$?
    i=$((i+1))
done
exit $RET

información relacionada