Arctelix
Arctelix

Reputation: 4576

bash command substitution on external script function receives incorrect exit status

This example was tested on Mac El Capitan with bash

main_script.sh:

NOTE: func_a and func_b are identical except for the line that the local variable output is declared.

func_a () {
    local output
    output="$(./external.sh some_function)"
    if [ $? -eq 0 ];then
        echo "A zero result ($?) -> $output <- end"
    else
        echo "A other result ($?) -> $output <- end"
    fi
}

func_b () {
    local output="$(./external.sh some_function)"
    if [ $? -eq 0 ];then
        echo "B zero result ($?) -> $output <- end"
    else
        echo "B other result ($?) -> $output <- end"
    fi
}

func_a
func_b

external.sh:

some_function () {
    echo "this is the output"
    return 1
}

"$@"

When i run main_script the output is:

A other result (1) -> this is the output <- end
B zero result (0) -> this is the output <- end

For what reason would the declaration of a local variable on the same line as the command substitiution affect the results? Could this be a bug or am i missing something?

Upvotes: 2

Views: 207

Answers (1)

mklement0
mklement0

Reputation: 439257

The reason is that $? in func_b reflects the success of the local builtin rather than the success of the command substitution ($(...)).

The local builtin succeeds if the assignment is syntactically correct - irrespective of whether any command substitution on the RHS fails or not.

Note that this applies analogously to the declare and export builtins.

To illustrate with a simple example:

declare output="$(false)"; echo $? # -> 0(!) - even though `false` obviously fails.

By contrast, if no builtin is involved - in the case of a simple variable assignment - a command substitution's failure is reflected in $?:

output="$(false)"; echo $? # -> 1(!) - simple assignment; $(...) exit code is reported

This counter-intuitive difference in behavior is explained by the fact that local / declare / export are builtins rather than part of the shell syntax.

As builtins (built-in commands), they are treated like commands, and commands are expected to signal their success/failure via their own exit code; in the case of said builtins, as stated, a syntactically correct assignment is considered success - in other words: if something could be assigned - even if that something is the null string due to a failing command substitution on the RHS - the builtin succeeded.

Upvotes: 2

Related Questions