views:

10581

answers:

7

I have a shell script that executes a number of commands, and if any of the commands exit with a non-zero exit code the shell script should exit.

+1  A: 

In bash this is easy, just tie them together with &&:

command1 && command2 && command3

You can also use the nested if construct:

if command1
   then
       if command2
           then
               do_something
           else
               exit
       fi
   else
       exit
fi
Martin W
+8  A: 

Turning on psychic debugging powers (as there's no actual question in your "question").

I' m assuming you're running Linux since it's tagged "bash" and you want a way to do it.

After each command, the exit code can be found in the $? variable so you would have something like:

ls -al file.ext
rc=$?
if [[ $rc != 0 ]] ; then
    exit $rc
fi

You need to be careful of piped commands since the $? only gives you the return code of the last element in the pipe so, in the code:

ls -al file.ext | sed 's/^/xx: /"

will not return an error code if the file doesn't exist (since the sed works).

paxdiablo
+6  A: 

"set -e" is probably the easiest way to do this. Just put that before any commands in your program.

Allen
What does it do? Any link to docs please?
Swaroop C H
+19  A: 

If you want to work with $?, you'll need to check it after each command, since $? is updated after each command exits. This means that if you execute a pipeline, you'll only get the exit code of the last process in the pipeline.

Another approach is to do this:

set -e
set -o pipefail

If you put this at the top of the shell script, it looks like bash will take care of this for you. As a previous poster noted, "set -e" will cause bash to exit with an error on any simple command. "set -o pipefail" will cause bash to exit with an error on any command in a pipeline as well.

See here or here for a little more discussion on this problem. Here is the bash manual section on the set builtin.

Jeff Hill
+1  A: 

If you just call exit in the bash with no parameters, it will return the exit code of the last command. Combined with OR the bash should only invoke exit, if the previous command fails. But I haven't tested this.

command1 || exit;
command2 || exit;

The Bash will also store the exit code of the last command in the variable $?.

ManuelFuenfrocken
+1  A: 

for bash:

# this will trap any errors or commands with non-zero exit status
# by calling function catch_errors()
trap catch_errors ERR;

#
# ... the rest of the script goes here
#  

function catch_errors() {
   # do whatever on errors
   # 
   #
   echo "script aborted, because of errors";
   exit 0;
}
Probably shouldn't "exit 0", since that indicates success.
nobar
+2  A: 

http://cfaj.freeshell.org/shell/cus-faq-2.html#11

  1. How do I get the exit code of cmd1 in cmd1|cmd2

    First, note that cmd1 exit code could be non-zero and still don't mean an error. This happens for instance in

    cmd | head -1

    you might observe a 141 (or 269 with ksh93) exit status of cmd1, but it's because cmd was interrupted by a SIGPIPE signal when "head -1" terminated after having read one line.

    To know the exit status of the elements of a pipeline cmd1 | cmd2 | cmd3

    a. with zsh:

    The exit codes are provided in the pipestatus special array. cmd1 exit code is in $pipestatus[1], cmd3 exit code in $pipestatus[3], so that $? is always the same as $pipestatus[-1].

    b. with bash:

    The exit codes are provided in the PIPESTATUS special array. cmd1 exit code is in ${PIPESTATUS[0]}, cmd3 exit code in ${PIPESTATUS[2]}, so that $? is always the same as ${PIPESTATUS: -1}.

    ...

    For more details see the following link.

Vladimir Graschenko