Assigning exit code to a shell local variable
Solution 1
local t1=$(exit 1)
tells the shell to:
- run
exit 1
in a subshell; - store its output (as in, the text it outputs to standard output) in a variable
t1
, local to the function.
It's thus normal that t1
ends up being empty.
($()
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. You can of course assign $?
to another variable:
function0()
{
(exit 1)
local t1=$?
echo "$t1"
}
Solution 2
Exit code was stored in $? variable. Using Command Substitution only capture the output, you should use (...) to create subshell:
#!/bin/bash
func() {
(exit 1)
local t1=$?
printf '%d\n' "$t1"
}
func
Solution 3
In bash
this works:
loc(){ local "x=$(exit "$1"):$?"
printf '$%s:\t%d\n' \
x "${x##*:}" \? "$?"
}
It has to do with the order of command evaluation and variable assignment. local
has a return value all its own - and it is the currently executing command, not the command substitution. The reason things like...
x=$(exit 1); echo "$?"
...can return 1 is because there never is a return in that command except for the subshell run to assign $x
's value - so $?
doesn't get clobbered as it does in practically every other case in which command substitutions are used.
Anyway, with local
it does get clobbered - but if you catch it at just the right time - which is while the expansions are still being evaluated and before local
's routines have a chance to clobber it - you can still assign it.
unset x; loc 130; echo "${x-\$x is unset}"
...prints...
$x: 130
$?: 0
$x is unset
You should know though that in many shells you cannot rely upon $?
being set mid-evaluation in that way. In fact, that's probably because those shells do not bother re-evaluating at every possible juncture as perhaps bash
does - which I would argue is probably better behavior than bash
's. Do you really want your interpreter recursively loop-evaluating values which are very likely to be overwritten before ever you have the chance to use them?
Anyway, that's how you can do that.
Solution 4
This does not answer this question exactly, but I think in majority of cases you would make decisions based on the acquired exit code later down the execution stream. If you need to check for success/failure exit code only – it can easily be achieved without storing the code into a variable:
if (exit 1); then
echo "Command succeeded, alles gut"
else
echo "Oi oi, Huston, we got alles kaputt 'round here"
fi
Solution 5
@mikeserv's answer is great, and provides explanation for behavior I had discovered but had no idea why it was happening.
I just wanted to add an easy way to avoid local
eating the exit code of a subshell is to do:
val_check_exit() {
local val=
val=$(echo "hi"; exit 1)
local res=$?
echo "val is ${val}, exit code ${res}"
}
val_check_exit
# outputs:
# val is hi, exit code 1
Related videos on Youtube
Gilles 'SO- stop being evil'
Updated on September 18, 2022Comments
-
Gilles 'SO- stop being evil' almost 2 years
#!/bin/bash function0() { local t1=$(exit 1) echo $t1 } function0
echo
prints empty value. I expected:1
Why doesn't
t1
variable get assigned the exit command's return value -1
? -
cuonglm about 9 years@Dani_l: Thanks, that's a mis-typo. Updated.
-
mikeserv about 9 yearsYou know, you can always put the return into the pipe, too. `$(trap 'printf "::ERRNO:$?"' 0; # now do whatever however - that trap will ensure the last string written is the last return for the whole substitution context.
-
phyatt over 7 yearsNote that Command Substitution only captures standard out unless redirected differently.
-
Nick Matteo over 5 yearsAll the claimed outputs are wrong, due to the fact that command substitution doesn't give the exit code, which is the whole point of the question. It's not clear what the "dirty trick" has to do with anything.
-
Cheetaiean over 4 yearsHow about if this was outside a function? I am running bash code in a Makefile and cannot use local. Without local the same problem persists as in the original question.
-
Stephen Kitt over 4 years@Cheetaiean please ask a new question with details of what you’re trying to do and the problems you’re having.
-
spawn over 3 yearsGoing a step further: I found this question because I wanted to capture the output of a command into a local variable and use the exit code afterwards. This can be done by simply declaring it first:
function0(){ local foo; foo=$(echo bar; exit 1); echo "returned $?"; }