5

I have a script that calls another script. When the child script fails, I'd like the parent to fail as well.

In the child script child_1.sh, I have something like this:

if [ $SOME_BAD_CONDITION ] ; then
  echo "Error message...."
  exit 1
fi

In the parent, I have this:

#!/bin/bash
set -e
#...
bash ./child_1.sh
echo "continuing to next step..."
bash ./child_2.sh
bash ./child_3.sh
#...

I've set up my environment so that $SOME_BAD_CONDITION will always happen, and the script exits as expected and the error message does print, but the parent script continues: the message "continuing..." is printed and the next script begins executing.

I thought that having set -e would ensure that my parent script fails if any child script exists with a non-zero exit code, but that doesn't seem to be happening. I'm not sure what I got wrong here...

bash version: 4.2.25


UPDATE:

I tried echoing $?:

bash ./child_1.sh
echo $?
echo "continuing to next step..."

The output looks like this:

Error message....
0
continuing to next step...

Why doesn't the exit code from the child make it into the parent?


ANSWER: The original code snippet was incomplete. The exit 1 was inside a code block that was piped to tee. My attempt to post a clean, short code sample ignored this because I did not realize how significant it was (I'm still fairly new to bash scripting). See my posted answer for details.

closed as unclear what you're asking by Gilles 'SO- stop being evil', jimmij, jasonwryan, Michael Homer, Anthon Feb 26 '15 at 5:36

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • @StéphaneChazelas: 4.2.25 – FrustratedWithFormsDesigner Feb 25 '15 at 17:33
  • Do you see the problem with that simple script, or only when there's more in that #... ellipsis after set -e? – Stéphane Chazelas Feb 25 '15 at 17:35
  • Does child_1.sh have a trap on EXIT? Did you try adding a echo "$?" after bash ./child_1.sh? – Stéphane Chazelas Feb 25 '15 at 17:40
  • @StéphaneChazelas: No trap in the child. I tried printing $? and it's always 0. – FrustratedWithFormsDesigner Feb 25 '15 at 18:29
  • 1
    The part that you posted looks fine, the issue is therefore in some part that you didn't post. Post some runnable code that would let us reproduce the problem. – Gilles 'SO- stop being evil' Feb 25 '15 at 23:39
4

So, I might have made an error in not posting enough details about the child script - I simplified it for the purpose of this question, but maybe too much. The exit statement was buried inside a code block (between { and }) which was piped to tee for logging:

{
  #...
  if [ $SOME_BAD_CONDITION ] ; then
    exit 1
  fi
  #...
} | tee -a $LOGFILE
echo "script ended at $date">>$LOGFILE

From what I understand, I always got a return code of 0 from this child script because the last echo was returning 0. I did some research and discovered $PIPESTATUS. I was able to use this to ensure that when my script tried to exit with exit code 1, it would be passed up to parent script:

{
  #...
} | tee -a $LOGFILE
EXIT_CODE=${PIPESTATUS[0]}
echo "script ended at $date">>$LOGFILE
exit $EXIT_CODE

Combined with John's suggestion, I have a solution that seems to be working.

2

Since your child processes exit with a proper zero/non-zero exit code convention, and given that you execute them sequentially, I'd say you could just use the && operator:

#!/bin/bash

./child_1.sh
[[ $? -ne 0 ]] && exit # Exit if non-zero exit code
./child_2.sh
./child_3.sh
./child_4.sh
exit 0

Here, [[ $? -ne 0 ]] && exit acts like:

if [ $? -ne 0 ]; then # If: last exit code is non-zero
    exit
fi

If you don't have anything to do between the calls, you could even use...

#!/bin/bash
./child_1.sh && ./child_2.sh && ./child_3.sh && ./child_4
exit $?

The && operator acts like a short-circuit AND operator, and a zero exit code is pretty much like a true boolean value. If at any time in the chain, a script exits with non-zero, the && will fail, and subsequents scripts shouldn't be called.

  • I added a debugging statement to print the value of $? and it prints 0. It looks like the exit code from the child script does not get picked up by the parent script. – FrustratedWithFormsDesigner Feb 25 '15 at 18:26
  • @FrustratedWithFormsDesigner There must be a problem with your child script. I tried it myself just now, and my parent script did get the correct exit code back. Make sure your child script exits as you expect it to. – John WH Smith Feb 25 '15 at 18:54
  • Yes, you were right. I had a problem in the child script, but it seems I over-simplified the child script in the original post, which is why no one caught it. – FrustratedWithFormsDesigner Feb 25 '15 at 19:21
0

Looks like your issue stems from how you throw the error in your child script.

From man set "if a simple command (see SHELL GRAMMAR above) exits with a non-zero status. The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in a if statement, part of an && or || list, or if the command's return value is being inverted via !"

Rather than using set -e, use a trap statement and throw an error. (If you need to use the conditional exit.

See http://mywiki.wooledge.org/BashFAQ/105

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