Variable definition are separate from assignment in bash [duplicate] - bash

This Bash snippet works as expected:
$ fun1() { x=$(false); echo "exit code: $?"; }
$ fun1
exit code: 1
But this one, using local, does not as I would have expected:
$ fun2() { local x=$(false); echo "exit code: $?"; }
$ fun2
exit code: 0
Can anyone explain why does local sweep the return code of the command?

The reason the code with local returns 0 is because $? "Expands to the exit status of the most recently executed foreground pipeline." Thus $? is returning the success of local
You can fix this behavior by separating the declaration of x from the initialization of x like so:
$ fun() { local x; x=$(false); echo "exit code: $?"; }; fun
exit code: 1

The return code of the local command obscures the return code of false

Related

Bash command substitution within a function does not return the return code from the command substitution [duplicate]

This Bash snippet works as expected:
$ fun1() { x=$(false); echo "exit code: $?"; }
$ fun1
exit code: 1
But this one, using local, does not as I would have expected:
$ fun2() { local x=$(false); echo "exit code: $?"; }
$ fun2
exit code: 0
Can anyone explain why does local sweep the return code of the command?
The reason the code with local returns 0 is because $? "Expands to the exit status of the most recently executed foreground pipeline." Thus $? is returning the success of local
You can fix this behavior by separating the declaration of x from the initialization of x like so:
$ fun() { local x; x=$(false); echo "exit code: $?"; }; fun
exit code: 1
The return code of the local command obscures the return code of false

How can I use local variables and keep the return code in bash? [duplicate]

This Bash snippet works as expected:
$ fun1() { x=$(false); echo "exit code: $?"; }
$ fun1
exit code: 1
But this one, using local, does not as I would have expected:
$ fun2() { local x=$(false); echo "exit code: $?"; }
$ fun2
exit code: 0
Can anyone explain why does local sweep the return code of the command?
The reason the code with local returns 0 is because $? "Expands to the exit status of the most recently executed foreground pipeline." Thus $? is returning the success of local
You can fix this behavior by separating the declaration of x from the initialization of x like so:
$ fun() { local x; x=$(false); echo "exit code: $?"; }; fun
exit code: 1
The return code of the local command obscures the return code of false

return value from subshell and output to local variables

I've found the strange behaviour for me, which I can't explain.
The following code is work OK:
function prepare-archive {
blah-blah-blah...
_SPEC_FILE=$(check-spec-file "$_GIT_DIR/packaging/")
exit $?
blah-blah-blah...
}
means I get value which I expect:
bash -x ./this-script.sh:
++ exit 1
+ _SPEC_FILE='/home/likern/Print/Oleg/print-service/packaging/print-service.spec
/home/likern/Print/Oleg/print-service/packaging/print-service2.spec'
+ exit 1
As soon as I add local definition to variable:
local _SPEC_FILE=$(check-spec-file "$_GIT_DIR/packaging/")
I get following:
bash -x ./this-script.sh:
++ exit 1
+ local '_SPEC_FILE=/home/likern/Print/Oleg/print-service/packaging/print-service.spec
/home/likern/Print/Oleg/print-service/packaging/print-service2.spec'
+ exit 0
$:~/MyScripts$ echo $?
0
Question: Why? What has happened? Can I catch output from subshell to local variable and check subshell's return value reliably?
P.S.: prepare-archive is called in the main shell script. The first exit is the exit from check-spec-file function, the second from prepare-archive function - this function itself is executed from main shell script. I return value from check-spec-file by exit 1, then pass this value to exit $?. Thus I expect they should be the same.
To capture subshell's exit status, declare the variable as local before the assignment, for example, the following script
#!/bin/sh
local_test()
{
local local_var
local_var=$(echo "hello from subshell"; exit 1)
echo "subshell exited with $?"
echo "local_var=$local_var"
}
echo "before invocation local_var=$local_var in global scope"
local_test
echo "after invocation local_var=$local_var in global scope"
produces the following output
before invocation local_var= in global scope
subshell exited with 1
local_var=hello from subshell
after invocation local_var= in global scope
From the bash manual, Shell Builtin Commands section:
local:
[...]The return status is zero unless local is used outside a function, an invalid name is supplied, or name is a readonly variable.
Hope this helps =)
As I use bash subshell parenthesis to group many echo commands I hit this strange problem.
In my case all I needed was to pass one value back to the calling shell so I just used the exit command
RET=0
echo RET: $RET
(echo hello
echo there
RET=123
echo RET: $RET
exit $RET)
RET=$?
echo RET: $RET
gives the following output
RET: 0
hello
there
RET: 123
RET: 123
without the exit command you will get this which is confusing:
RET: 0
hello
there
RET: 123
RET: 0

How to return from sourcing function in sourced code?

Consider foo.sh:
#!/bin/bash
function foo() {
source another.sh
echo "This shouldn't be executed. Return code: $?"
return 0
}
foo
echo "Return code: $?"
Then another.sh:
echo "Inside another.sh"
return 1
Running ./foo.sh prints:
Inside another.sh
This shouldn't be executed. Return code: 1
Return code: 0
Is there an alternative method to include a source file into another such that the return command would return from the function enclosing include command rather than from the command itself?
One option is to propagate the return code in foo.sh:
source another.sh || return $?
Then:
$ ./foo.sh
Inside another.sh
Return code: 1
Alternatively, exit from the whole script in another.sh:
exit 1
Then:
$ ./foo.sh
Inside another.sh
$ echo $?
1

Why does "local" sweep the return code of a command?

This Bash snippet works as expected:
$ fun1() { x=$(false); echo "exit code: $?"; }
$ fun1
exit code: 1
But this one, using local, does not as I would have expected:
$ fun2() { local x=$(false); echo "exit code: $?"; }
$ fun2
exit code: 0
Can anyone explain why does local sweep the return code of the command?
The reason the code with local returns 0 is because $? "Expands to the exit status of the most recently executed foreground pipeline." Thus $? is returning the success of local
You can fix this behavior by separating the declaration of x from the initialization of x like so:
$ fun() { local x; x=$(false); echo "exit code: $?"; }; fun
exit code: 1
The return code of the local command obscures the return code of false

Resources