2

I have a following script sandbox.sh,

#!/bin/bash
set -eu -o pipefail -E

function func1() {
  echo "FUNC1"
  exit 1
}

function func2() {
  local ret
  ret=$(func1)
  echo $ret
  echo "(func2)This line shouldn't be reached:'${?}'" >&2
}

var=$(func1) # The Line
echo "main:This line shouldn't be reached:'${var}':'${?}'" >&2

(GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu))

This stops executing expectedly,

$ bash -eu sandbox.sh 
$ 

However, if I modify "The Line" to var=$(func2) to call func1 through func2, it will give me following output

$ bash sandbox.sh 
(func2)This line shouldn't be reached:'0'
main:This line shouldn't be reached:'FUNC1':'0'
$ 

To me, it seems command substitution behaves differently when it is placed inside a function, but I don't see why bash is designed so. Also it is a quite possible situation where a function's output is used by another and such a difference is confusing.

NOTE: If I rewrite func2 like following,

function func2() {
  func1
}

The script stops at The Line. However, programmers quite often want to manipulate output from func1, I believe.

  • 3
    This has nothing to do with functions, but with subshells (ie with your $(...) command substitutions). set -e / -o errexit is not inherited in subshells. Simpler example: bash -c 'set -e; echo $(false; echo survived)'. If you had used var=$(set -e; func2) in "The Line", the "shouldn't be reached" lines wouldn't have been reached. – mosvy Sep 14 '19 at 2:09
  • 1
    Another option is to add shopt -s inherit_errexit at the beginning of your script (also enabled in posix mode). Notice that set -e / errexit is independent of the ERR trap and is not affected by set -E / errtrace – mosvy Sep 14 '19 at 2:20
  • @mosvy, Thanks, set -e made my script work as intended. But it also made puzzled me a bit more. Why don't I need to add set -e to the line that performs command substitution in func2? – Hiroshi_U Sep 14 '19 at 2:21
  • 1
    @mosvy, note that inherit_errexit is on when bash is running as sh. I wouldn't say the idea is right, I'm not sure it could ever be implemented with a clear and consistent API. To me, it's better avoided, reserved for the most basic of scripts (i.e. with the real-life definition of script, when you just put in a file a plain sequence of commands run one after the other). – Stéphane Chazelas Sep 14 '19 at 6:12
  • 1
    @mosvy You mentioned in a flagging message that I put this question on hold in order to reduce its visibility. This is not so. I put it on hold because I honestly thought it was a duplicate. I'm reopening it now because I believe that you may have a good answer for this question. – Kusalananda Sep 14 '19 at 23:14

Your Answer

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

Browse other questions tagged or ask your own question.