Bash.Вернуть два функциональных уровня (два вложенных вызова) - PullRequest
1 голос
/ 25 сентября 2019

Мне нужно знать, есть ли у Bash решение для моего случая.Мне нужно после некоторых условий сделать «двойной возврат».Я имею в виду, чтобы выполнить возврат функции, а также вернуть родительскую функцию, чтобы пропустить оставшуюся часть кода этой родительской функции.

Я знаю, что могу сделать условное использование возвращаемых функцией значений для достижения этой цели.Но я хотел бы знать, есть ли в Bash что-то вроде "break 2" для функций.Я не хочу, если возможно, изменить код родительской функции, потому что, как вы можете себе представить, в моем реальном скрипте есть десятки функций, и я не хочу изменять их все.

Пример:

#!/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

Ответы [ 3 ]

1 голос
/ 26 сентября 2019

Почему бы вам не вернуть статус выхода из функции и не добавить оператор if в main, как это обычно делается на любом другом языке программирования / написания сценариев?

#!/bin/bash

function sublevelone() {
    echo "sublevelone"
    [ 0 -eq 1 ]
    return $? # Returns 1 in this case because 0 != 1
}

function main() {
    sublevelone
    [ $? -eq 0 ] || return 1 # Return in case of error
    echo "This is the part of the code to being avoid executed"
}

main
exit 0
1 голос
/ 26 сентября 2019

Это довольно странно, но если вы используете скобки для определения main, она выполнит функцию в под-оболочке, а затем вы сможете выйти из этой оболочки из внутренней функции.Тем не менее, я думаю, что, вероятно, более уместно использовать return для отправки значения назад, которое вы можете проверить в родительской функции.

    #!/bin/bash
function leveltwo() {
        echo "two"
        exit
}
function levelone() (
        echo "one"
        leveltwo
        echo "three"
)

levelone
echo "four"

Напечатает:
one
two
four

1 голос
/ 25 сентября 2019

Я не знаю, что подумают эксперты по 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
}

Это использует ловушку DEBUG и флаг extdebug:

extdebug
    If  set  at  shell  invocation,  arrange  to execute the
    debugger profile before the shell starts,  identical  to
    the  --debugger option.  If set after invocation, behav-
    ior intended for use by debuggers is enabled:
    1.     The -F option to the declare builtin displays the
           source file name and line number corresponding to
           each function name supplied as an argument.
    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.
    4.     BASH_ARGC and BASH_ARGV are updated as  described
           in their descriptions above.
    5.     Function  tracing  is  enabled: command substitu-
           tion, shell functions, and subshells invoked with
           ( command ) inherit the DEBUG and RETURN traps.
    6.     Error  tracing  is enabled: command substitution,
           shell functions, and  subshells  invoked  with  (
           command ) inherit the ERR trap.

Пример использования:

#!/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

Результат:

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
...