Reputation: 1609
Below is the sample scenario :-
There is a sample function defined that is echoing some text, as well as setting some exit code using return. There is another script that is calling this function. Below is the simplified code :-
~/playground/octagon/bucket/test/sample $
pwd
/Users/mogli/playground/octagon/bucket/test/sample
~/playground/octagon/bucket/test/sample $
cat functions.sh
myfunc() {
echo "This is output $1"
return 3
}
~/playground/octagon/bucket/test/sample $
cat example.sh
. functions.sh
function example(){
myfunc_out=$(myfunc $1); myfunc_rc=$?
echo "myfunc_out is: $myfunc_out"
echo "myfunc_rc is: $myfunc_rc"
}
example $1
~/playground/octagon/bucket/test/sample $
sh example.sh 44
myfunc_out is: This is output 44
myfunc_rc is: 3
Now, if I use local for variables that are used to store function return value and exit code in example.sh, then exit code is not coming correctly. Please find below modified example.sh :-
~/playground/octagon/bucket/test/sample $
cat example.sh
. functions.sh
function example(){
local myfunc_out=$(myfunc $1); local myfunc_rc=$?
echo "myfunc_out is: $myfunc_out"
echo "myfunc_rc is: $myfunc_rc"
}
example $1
~/playground/octagon/bucket/test/sample $
sh example.sh 44
myfunc_out is: This is output 44
myfunc_rc is: 0
Upvotes: 2
Views: 225
Reputation: 212664
When you write:
var=$(cmd)
the output of cmd
is assigned to var
(without word splitting) and $?
is set to the value returned by cmd
.
When you write:
var=$(cmd1) cmd2
cmd1
is executed and its output (without word splitting) is assigned to the variable var
in the environment of cmd2
, which is then executed. $?
is set to the value returned by cmd2
.
When you write:
cmd1 var=$(cmd2)
cmd2
is executed, the string var=output of cmd2
is subject to word splitting and passed as argument(s) to cmd1
, and $?
is set to the value returned by cmd1
. (In almost all cases you want to supress the word splitting and instead write cmd1 var="$(cmd2)"
, which will guarantee that only one argument is passed.)
local
is a command, and local myfunc_out=$(myfunc $1)
is of the 3rd form (with a caveat), so it sets $?
to the value returned by local
. Note that if the output of myfunc $1
contains whitespace, word splitting does not take place. To quote the manpage: Assignment statements may also appear as arguments to the alias, declare, typeset, export, readonly, and local builtin commands
, so the string counts as a variable assignment and word splitting is not done.
In short, local
has an exit value, and it is being used to set $?
Instead of making the assignment an argument to local
, you could use:
local myfunc_out myfunc_rc
myfunc_out="$(myfunc $1)"; myfunc_rc=$?
Note that the double quotes are not strictly necessary here, as word splitting does not take place in an assignment, but using them is definitely good practice.
Upvotes: 4