Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why using Bash readonly variable to capture output fails to capture return code $?

Tags:

variables

bash

Here's example that tries to execute command and checks if it was executed successfully, while capturing it's output for further processing:

#!/bin/bash

readonly OUTPUT=$(foo)
readonly RES=$?

if [[ ${RES} != 0 ]]
then
    echo "failed to execute foo"
    exit 1
else
    echo "foo success: '${OUTPUT}'"
fi

It reports that it was a success, even there is no such foo executable. But, if I remove readonly from OUTPUT variable, it preserves erroneous exit code and failure is detected.

I try to use readonly as for "defensive programming" technique as recommended somewhere... but looks like it bites itself in this case.

Is there some clean solution to preserve readonly while still capturing exit code of command/subshell? It would be disappointing that one has to remember this kind of exceptional use case, or revert to not using readonly ever...

Using Bash 4.2.37(1) on Debian Wheezy.

like image 739
Vincas Dargis Avatar asked Sep 26 '16 06:09

Vincas Dargis


People also ask

What does readonly do in bash?

The values of variables with the readonly attribute cannot be changed by subsequent assignment, nor can those variables be unset by the unset utility. If the name of a variable is followed by = word, then the value of that variable shall be set to word.

What is readonly variable in shell script?

Read-only VariablesShell provides a way to mark variables as read-only by using the read-only command. After a variable is marked read-only, its value cannot be changed. For example, the following script generates an error while trying to change the value of NAME − #!/bin/sh NAME="Zara Ali" readonly NAME NAME="Qadiri"

How do I change a read only variable in Linux?

The shell provides a way to protect variables as read-only by using the readonly command. After a variable is marked read-only, we cannot change the value of the variable. As we can see from the output, we cannot assign to the variable declared as readonly. If we drop "$", we get an error.


1 Answers

The problem is that readonly is its own command and the exit code that it returns is its own exit code, not the exit code of the command substitution.

From help readonly:

Exit Status:
Returns success unless an invalid option is given or NAME is invalid.

So, you need to use two separate commands:

$ output=$(false)
$ readonly res=$?
$ readonly output

This saves the exit code that you want:

$ echo $res
1

Short of entering a debugger, there is no way to unset a readonly variable. So, don't set a variable readonly unless you want it to stay constant for the remainder of the bash session.

Variation

The two readonly commands can be combined into one (hat tip: Chepner):

$ output=$(false)
$ readonly output res=$?
$ echo $res
1

Aside

It is best practices to use lower- or mixed-case names for your variables. The system uses all upper-case names and you don't want to overwrite a system variable accidentally.

like image 56
John1024 Avatar answered Oct 25 '22 11:10

John1024