37

The set -e command makes a bash script fail immediately when any command returns an non-zero exit code.

  1. Is there an easy and elegant way to disable this behaviour for an individual command within a script?

  2. At which places is this functionality documented in the Bash Reference Manual (http://www.gnu.org/software/bash/manual/bashref.html)?

30
  1. Something like this:

    #!/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
    

    Run:

    $ ./test.sh
    hi
    ./test.sh: line 7: aoeuidhtn: command not found
    next line
    ./test.sh: line 11: ao: command not found
    
  2. It's described in set builtin help:

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

The same is documented here: https://www.gnu.org/software/bash/manual/bashref.html#The-Set-Builtin.

  • Thanks! I found another possibility: #!/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 normal script exit – Gustave Jul 14 '15 at 16:20
23

An alternative to unsetting the bail on error would be to force a success no matter what. You can do something like this:

cmd_to_run || true

That will return 0 (true), so the set -e shouldn't be triggered

  • 3
    faulty_cmd || : is another popular idiom for this. (The : is a command synonymous to true). – ulidtko Aug 26 '16 at 12:24
  • 3
    @ulidtko - interesting. Led me down the rabbit hole to find this stackoverflow.com/questions/3224878/… to get the history on true vs. : – ernie Aug 26 '16 at 17:55
12

If you are trying to catch the return/error code (function or fork), this works:

function xyz {
    return 2
}

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

If the the "exit immediately shell option" applies or is ignored depends on the context of the executed command (see Bash Reference Manual section on the Set Builtin - thanks to Arkadiusz Drabczyk).

Especially, the option is ignored if a command is part of the test in an if statement. Therefore it is possible to execute a command and check for its success or failure within an "exit immediately context" using an if statement like this:

#!/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."

It is possible to omit the "then" statement and use fewer lines:

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

Another approach, which I find fairly straightforward (and applies to other set options in addition to -e):

Make use of $- to restore settings.

For example:

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

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

Though for -e specifically, the options others have mentined (|| true or "put inside an if") may be more idiomatic.

0

I actually had a similar question recently (though I didn't post, I got around to it), and, from what I can see, it seems like just using set +e before the command and set -e afterward works most elegantly. Here's an example, grabbing the response of the command and not letting the error throw it away.

#!/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

This grabs the output of 'fortune', checking its exit status, and echoes and says it. I think this is what you were asking for, or at least something similar? Anyway, hope this helps.

  • To clarify, the bit in curly parentheticals being redirected to /dev/null is what you're after, I believe. It makes the command have no ouput and checks its error status without exiting the program. – Addison Crump Jul 14 '15 at 15:31
0

I like to start subshell if want to change something temporarily. Below command demonstrates that first bad_command is ignored and second aborts execution.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.