¿Cómo deshabilitar set -e para un comando individual?

36

El comando set -e hace que un script bash falle inmediatamente cuando cualquier comando devuelve un código de salida distinto de cero.

  1. ¿Existe una manera fácil y elegante de deshabilitar este comportamiento para un comando individual dentro de un script?

  2. ¿En qué lugares está documentada esta funcionalidad en el Manual de referencia de Bash ( http://www.gnu.org/software/bash/manual/bashref.html )?

Gustave
fuente

Respuestas:

29
  1. Algo como esto:

    #!/usr/bin/env bash
    
    set -e
    echo hi
    
    # disable exitting on error temporarily
    set +e
    aoeuidhtn
    echo next line
    
    # bring it back
    set -e
    ao
    
    echo next line

    Correr:

    $ ./test.sh
    hi
    ./test.sh: line 7: aoeuidhtn: command not found
    next line
    ./test.sh: line 11: ao: command not found
  2. Se describe en la setayuda integrada:

    $ type set
    set is a shell builtin
    $ help set
    (...)
    Using + rather than - causes these flags to be turned off.

Lo mismo se documenta aquí: https://www.gnu.org/software/bash/manual/bashref.html#The-Set-Builtin .

Arkadiusz Drabczyk
fuente
¡Gracias! Encontré otra posibilidad: #! / Bin / bash set -e # Descomente la siguiente línea para ver el efecto set -e: #blubb if blubb; luego echo "El comando blubb fue exitoso". else echo "El comando blubb falló. Código de salida: $?" fi echo salida normal del script
Gustave
22

Una alternativa para cancelar la fianza por error sería forzar un éxito sin importar qué. Puedes hacer algo como esto:

cmd_to_run || true

Eso devolverá 0 (verdadero), por lo que el conjunto -e no debe activarse

ernie
fuente
3
faulty_cmd || :Es otro idioma popular para esto. (El :es un comando sinónimo de true).
ulidtko
3
@ulidtko: interesante. Me llevó por la madriguera del conejo para encontrar este stackoverflow.com/questions/3224878/… para obtener la historia de verdadero vs.:
ernie
12

Si está tratando de atrapar el código de retorno / error (función o bifurcación), esto funciona:

function xyz {
    return 2
}

xyz && RC=$? || RC=$?
h0tw1r3
fuente
8

Si se aplica o se ignora la "opción de shell de salida inmediata", depende del contexto del comando ejecutado (consulte la sección Manual de referencia de Bash en Set Builtin , gracias a Arkadiusz Drabczyk).

Especialmente, la opción se ignora si un comando es parte de la prueba en una declaración if. Por lo tanto, es posible ejecutar un comando y verificar su éxito o falla dentro de un "contexto inmediato de salida" usando una instrucción if como esta:

#!/bin/bash

set -e

# Uncomment next line to see set -e effect:
#blubb

if blubb; then
  echo "Command blubb was succesful."
else 
  echo "Command blubb failed. Exit code: $?"
fi
echo "Script exited normally."

Es posible omitir la declaración "entonces" y usar menos líneas:

if blubb; then :;
else echo "Command blubb failed. Exit code: $?"; fi
Gustave
fuente
2

Otro enfoque, que encuentro bastante sencillo (y se aplica a otras setopciones además de -e):

Utilice $-para restaurar la configuración.

Por ejemplo:

oldopt=$-
set +e
# now '-e' is definitely disabled.
# do some stuff...

# Restore things back to how they were
set -$oldopt

Aunque -eespecíficamente, las opciones que otros han mencionado ( || trueo "puesto dentro de un if") pueden ser más idiomáticas.

jwd
fuente
0

En realidad, tuve una pregunta similar recientemente (aunque no publiqué, me di cuenta), y, por lo que puedo ver, parece que solo uso set + e antes del comando y set -e después funciona de manera más elegante. Aquí hay un ejemplo, agarrando la respuesta del comando y no dejando que el error lo descarte.

#!/bin/sh

args=""
for argcol in $*
do
    args="${args} ${argcol}"
done
fortunevar=""
fortfail=""
{
    set +e
    fortunevar=`fortune $args`
    fortfail=$?
    set -e
} &> /dev/null
if [ $fortfail == 0 ]
then
    echo ${fortunevar}
    say ${fortunevar}
else
    echo misfortune: an illegal option was detected!
    echo misfortune: usage: misfortune [-afilosw] [-m pattern][ [#%] file/directory/all]
fi

Esto toma la salida de 'fortuna', verifica su estado de salida, y hace eco y lo dice. Creo que esto es lo que estabas pidiendo, o al menos algo similar. De todos modos, espero que esto ayude.

Addison Crump
fuente
Para aclarar, el bit en paréntesis rizados que se redirige a / dev / null es lo que buscas, creo. Hace que el comando no tenga salida y verifica su estado de error sin salir del programa.
Addison Crump
0

Me gusta iniciar subshell si quiero cambiar algo temporalmente. El siguiente comando demuestra que el primer bad_command se ignora y el segundo aborta la ejecución.

bash -c 'set -e ;\
( set +e; bad_command ; echo still here ) ;\
echo even here ; \
bad_command ; \
echo but not here;'
noonex
fuente