Exit code of variable assignment to command substitution in Bash

assign exit code to variable bash
bash get exit code of command
bash command substitution exit code
bash compare command exit code
bash exit code
shell script return value to variable
bash check exit code
bash execute command in variable

I am confused about what error code the command will return when executing a variable assignment plainly and with command substitution:

a=$(false); echo $?

It outputs 1, which let me think that variable assignment doesn't sweep or produce new error code upon the last one. But when I tried this:

false; a=""; echo $?

It outputs 0, obviously this is what a="" returns and it override 1 returned by false.

I want to know why this happens, is there any particularity in variable assignment that differs from other normal commands? Or just be cause a=$(false) is considered to be a single command and only command substitution part make sense?

-- UPDATE --

Thanks everyone, from the answers and comments I got the point "When you assign a variable using command substitution, the exit status is the status of the command." (by @Barmar), this explanation is excellently clear and easy to understand, but speak doesn't precise enough for programmers, I want to see the reference of this point from authorities such as TLDP or GNU man page, please help me find it out, thanks again!


Upon executing a command as $(command) allows the output of the command to replace itself.

When you say:

a=$(false)             # false fails; the output of false is stored in the variable a

the output produced by the command false is stored in the variable a. Moreover, the exit code is the same as produced by the command. help false would tell:

false: false
    Return an unsuccessful result.

    Exit Status:
    Always fails.

On the other hand, saying:

$ false                # Exit code: 1
$ a=""                 # Exit code: 0
$ echo $?              # Prints 0

causes the exit code for the assignment to a to be returned which is 0.


EDIT:

Quoting from the manual:

If one of the expansions contained a command substitution, the exit status of the command is the exit status of the last command substitution performed.

Quoting from BASHFAQ/002:

How can I store the return value and/or output of a command in a variable?

...

output=$(command)

status=$?

The assignment to output has no effect on command's exit status, which is still in $?.

Assigning exit code to a shell local variable, is known as command substitution.) The exit code is always assigned to $? , so you can do function0() { (exit 1) echo "$?" } to get the effect you're looking for. causes the exit code for the assignment to a to be returned which is 0. EDIT: Quoting from the manual: If one of the expansions contained a command substitution, the exit status of the command is the exit status of the last command substitution performed. Quoting from BASHFAQ/002:


Note that this isn't the case when combined with local, as in local variable="$(command)". That form will exit successfully even if command failed.

Take this Bash script for example:

#!/bin/bash

function funWithLocalAndAssignmentTogether() {
    local output="$(echo "Doing some stuff.";exit 1)"
    local exitCode=$?
    echo "output: $output"
    echo "exitCode: $exitCode"
}

function funWithLocalAndAssignmentSeparate() {
    local output
    output="$(echo "Doing some stuff.";exit 1)"
    local exitCode=$?
    echo "output: $output"
    echo "exitCode: $exitCode"
}

funWithLocalAndAssignmentTogether
funWithLocalAndAssignmentSeparate

Here is the output of this:

nick.parry@nparry-laptop1:~$ ./tmp.sh 
output: Doing some stuff.
exitCode: 0
output: Doing some stuff.
exitCode: 1

This is because local is actually a builtin command, and a command like local variable="$(command)" calls local after substituting the output of command. So you get the exit status from local.

bash - Assigning exit code to a shell local variable, is known as command substitution.) The exit code is always assigned to $? , so you can do function0() { (exit 1) echo "$?" } to get the effect  bash - local variable assignment not respecting command substitution exit status - local-var-test.sh Code Revisions 1.


I came across the same problem yesterday (Aug 29 2018).

In addition to local mentioned in Nick P.'s answer and @sevko's comment in the accepted answer, declare in global scope also has the same behavior.

Here's my Bash code:

#!/bin/bash

func1()
{
    ls file_not_existed
    local local_ret1=$?
    echo "local_ret1=$local_ret1"

    local local_var2=$(ls file_not_existed)
    local local_ret2=$?
    echo "local_ret2=$local_ret2"

    local local_var3
    local_var3=$(ls file_not_existed)
    local local_ret3=$?
    echo "local_ret3=$local_ret3"
}

func1

ls file_not_existed
global_ret1=$?
echo "global_ret1=$global_ret1"

declare global_var2=$(ls file_not_existed)
global_ret2=$?
echo "global_ret2=$global_ret2"

declare global_var3
global_var3=$(ls file_not_existed)
global_ret3=$?
echo "global_ret3=$global_ret3"

The output:

$ ./declare_local_command_substitution.sh 2>/dev/null 
local_ret1=2
local_ret2=0
local_ret3=2
global_ret1=2
global_ret2=0
global_ret3=2

Note the values of local_ret2 and global_ret2 in the output above. The exit codes are overwritten by local and declare.

My Bash version:

$ echo $BASH_VERSION 
4.4.19(1)-release

bash, bash - local variable assignment not respecting command substitution exit status - local-var-test.sh. the output produced by the command false is stored in the variable a. Moreover, the exit code is the same as produced by the command. help false would tell: false: false Return an unsuccessful result. Exit Status: Always fails. On the other hand, saying: $ false # Exit code: 1 $ a="" # Exit code: 0 $ echo $?


(not an answer to original question but too long for comment)

Note that export A=$(false); echo $? outputs 0! Apparently the rules quoted in devnull's answer no longer apply. To add a bit of context to that quote (emphasis mine):

3.7.1 Simple Command Expansion

...

If there is a command name left after expansion, execution proceeds as described below. Otherwise, the command exits. If one of the expansions contained a command substitution, the exit status of the command is the exit status of the last command substitution performed. If there were no command substitutions, the command exits with a status of zero.

3.7.2 Command Search and Execution [ — this is the "below" case]

IIUC the manual describes var=foo as special case of var=foo command... syntax (pretty confusing!). The "exit status of the last command substitution" rule only applies to the no-command case.

While it's tempting to think of export var=foo as a "modified assignment syntax", it isn't — export is a builtin command (that just happens to take assignment-like args).

=> If you want to export a var AND capture command substitution status, do it in 2 stages:

A=$(false)
# ... check $?
export A

This way also works in set -e mode — exits immediately if the command substitution return non-0.

Bash variables and command substitution, Variables can be used, at the very least, to make code more readable for humans​: All of these examples would cause Bash to throw an error: output, that output, presumably just text, can be assigned to a variable like any other value: How to get the exit code of a command such as date and date-foo-bar. From the above outputs, it is clear that the exit code is 0 indicates that date command was successful. Further, the exit code is 127 (non-zero) as the nonexistant-command was not successful.


Command Substitution, Command substitution reassigns the output of a command [1] or even A safer way to assign a list of files to a parameter is with an array. in $variable # # Hit any key except RETURN, and the output is "You hit 1 key. This, however, forks a new process, #+ so the line of code executes slower than the above version. If the value you assign to a variable includes spaces, they must be in quotation marks when you assign them to the variable. This is because, by default, Bash uses a space as a delimiter. Here’s an example: site_name=How-To Geek. Bash sees the space before “Geek” as an indication that a new command is starting.


Linux Bash Command, These new commands have the same status as system commands in directories such as `/bin', allowing users or groups Command history and history expansion are enabled by default. Bash can be configured to exit when it encounters unreferenced variables. If no value is given, a variable is assigned the null string. To assign output of any shell command to variable in bash, use the following command substitution syntax: var =$ (command-name-here) var =$ (command-name-here arg1) var =$ (/ path / to / command) var =$ (/ path / to / command arg1 arg2)


Bash Assign Output of Shell Command To Variable, How do I assign the output of a shell command to a shell variable under Unix to variable in bash, use the following command substitution syntax: of 2 commands depending on the results (i've tried using the exit code but it  Command substitution. The standard output of a command can be encapsulated, much like a value can be stored in a value, and then expanded by the shell. This is known as command substitution. From the Bash documentation: Command substitution allows the output of a command to replace the command itself.