I need to know if Bash has some solution for my case. I need after some conditions to do a "double return". I mean, to perform a return of a function and also return the parent function to skip the rest of the code of that parent function.
I know that I can do a conditional using function return values to achieve this. But I'd like to know if in Bash exist something like "break 2" for functions. I don't want if possible to modify the code of the parent function because as you can imagine, in my real script there are dozens of functions and I don't want to modify all of them.
Example:
#!/bin/bash
function sublevelone() {
echo "sublevelone"
# Return 2, or break 2 or something :D
}
function main() {
sublevelone
echo "This is the part of the code to being avoid executed"
}
main
I don't know what the bash experts will think, but this works at least for simple cases:
multireturn(){
[ -n "$1" ] && poplevel="$1"
if [ "$poplevel" -ge 0 ]; then
trap multireturn DEBUG
shopt -s extdebug
(( poplevel-- ))
return 2
else
shopt -u extdebug
trap - DEBUG
return 0
fi
}
This makes use of the DEBUG trap and the extdebug flag:
trap [-lp] [[arg] sigspec ...]
[...] If a sigspec is DEBUG, the command arg is exe‐
cuted before every simple command, for command, case command,
select command, every arithmetic for command, and before the
first command executes in a shell function [...]
shopt [-pqsu] [-o] [optname ...]
[...]
extdebug
If set at shell invocation, or in a shell startup file,
arrange to execute the debugger profile before the shell
starts, identical to the --debugger option. If set af‐
ter invocation, behavior intended for use by debuggers
is enabled:
[...]
2. If the command run by the DEBUG trap returns a
non-zero value, the next command is skipped and
not executed.
3. If the command run by the DEBUG trap returns a
value of 2, and the shell is executing in a sub‐
routine (a shell function or a shell script exe‐
cuted by the . or source builtins), the shell
simulates a call to return.
[...]
5. Function tracing is enabled: command substitu‐
tion, shell functions, and subshells invoked with
( command ) inherit the DEBUG and RETURN traps.
Example usage:
#!/bin/bash
multireturn(){
[ -n "$1" ] && poplevel="$1"
if [ "$poplevel" -ge 0 ]; then
trap multireturn DEBUG
shopt -s extdebug
(( poplevel-- ))
return 2
else
shopt -u extdebug
trap - DEBUG
return 0
fi
}
# define 8 levels of function calls
# (level N prints output, calls level N+1, then prints more output)
for i in $(seq 1 8); do
eval \
'level'$i'(){
echo -n " '$i'"
level'$((i+1))'
echo -n "('$i')"
}'
done
# final level calls multireturn
level9(){
echo -n " 9"
multireturn $n
echo -n "(9)"
}
# test various skip amounts
for i in $(seq 0 10); do
echo -n "$i:"
n=$i
level1
echo .
done
echo
echo done
Result:
0: 1 2 3 4 5 6 7 8 9(9)(8)(7)(6)(5)(4)(3)(2)(1).
1: 1 2 3 4 5 6 7 8 9(8)(7)(6)(5)(4)(3)(2)(1).
2: 1 2 3 4 5 6 7 8 9(7)(6)(5)(4)(3)(2)(1).
3: 1 2 3 4 5 6 7 8 9(6)(5)(4)(3)(2)(1).
4: 1 2 3 4 5 6 7 8 9(5)(4)(3)(2)(1).
5: 1 2 3 4 5 6 7 8 9(4)(3)(2)(1).
6: 1 2 3 4 5 6 7 8 9(3)(2)(1).
7: 1 2 3 4 5 6 7 8 9(2)(1).
8: 1 2 3 4 5 6 7 8 9(1).
9: 1 2 3 4 5 6 7 8 9.
10: 1 2 3 4 5 6 7 8 9
done
Note that every function that will be short-circuited should contain at least one additional command after the call to multireturn (or the function that invoked it). If it doesn't, the DEBUG trap will be invoked in the wrong context and an extra level will be skipped. For example, compare what happens above if either the echo -n "('$i')" or echo -n "(9)" line is deleted.
Note also that multireturn is non-reentrant.
This is kinda whacky but if you use parentheses to define levelone, it will execute the function in a subshell and then you can exit out of that shell from an inner function. That said, I think it's more appropriate to use return to send back value that you check for in the parent function.
#!/bin/bash
function leveltwo() {
echo "two"
exit
}
function levelone() (
echo "one"
leveltwo
echo "three"
)
levelone
echo "four"
Will print:
one
two
four
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With