Search code examples
bashexitexit-codesubshell

How can I make one bash subshell exit the main calling shell script?


Having the following bash script:

#!/bin/bash

set -e

function foo() {
  # commands that might fails and I want to exit my script
  ...
  echo "result I need as output"
}

my_var=$(foo)

echo "I don't want this if there is an error inside foo"

Using set -e (in bash 4.4.19) does not seem to work with subshells i.e. the last echo command is still being executed). How can I write the code to make the script exit if any of the commands inside foo terminate with non-zero exit code.

I am using bash GNU bash, version 4.4.19(1)-release (x86_64-apple-darwin16.7.0) and the result of calling my script is (where the dots are replaced with an invalid command head -this:

$ ./my_script
head: illegal option -- t
usage: head [-n lines | -c bytes] [file ...]
I don't want this if there is an error inside foo

Solution

  • Changed from comments

    the exit status of a pipeline command is the exit status of the last command, this can be changed using set -o pipefail, so that pipeline exit status will be <>0 is any command exit status is <>0.

    First answer

    as you used the -e option it is sufficient that the function returns a non 0 exit code for example return 1

    in a more general case (without set -e), it can be better to use an explicit exit

    my_var=$(foo) || exit 1
    

    can be sufficient because error could be written on standard error (inherited) by subshell.

    otherwise reading carefully manual can explain why it doesn't work as you expected

    set -e

    Exit immediately if [...] returns 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 an if statement, part of any command executed in a && or || list except the command following the final && or ||, [...].

    This option applies to the shell environment and each subshell environment separately (see Command Execution Environment), and may cause subshells to exit before executing all the commands in the subshell.

    [...]

    And from Command Execution Environment

    Subshells spawned to execute command substitutions inherit the value of the -e option from the parent shell. When not in POSIX mode, Bash clears the -e option in such subshells.