【问题标题】:Behavior of the 'return' statement in Bash functionsBash 函数中“return”语句的行为
【发布时间】:2011-10-29 21:33:00
【问题描述】:

我无法理解 Bash 中内置的 return 的行为。这是一个示例脚本。

#!/bin/bash

dostuff() {
    date | while true; do
        echo returning 0
        return 0
        echo really-notreached
    done

    echo notreached
    return 3
}

dostuff
echo returncode: $?

这个脚本的输出是:

returning 0
notreached
returncode: 3

但是,如果 date | 从第 4 行中删除,则输出与我预期的一样:

returning 0
returncode: 0

似乎上面使用的return 语句的行为方式与我认为break 语句的行为方式相同,但仅当循环位于管道的右侧时。为什么会这样?我在Bash man page 或网上找不到任何解释这种行为的东西。该脚本在 Bash 4.1.5 和 Dash 0.5.5 中的行为方式相同。

【问题讨论】:

  • 有趣。是的,return 的行为似乎有点像 break;还可以在 if 语句中使用 return,您可以看到这种情况发生。除非 if 表达式非常简单。

标签: bash function return


【解决方案1】:

介绍 Bash 的这个有趣的特性...

  • if 内返回(或任何带有 if/while/... 等表达式的控制命令)

  • if 内返回简单和不太简单的表达式

子shell的解释很好。控制从当前的子外壳返回。这可能是 Bash 函数。或者它可能是任何带有表达式的嵌套控制命令导致子shell被调用。

  1. 对于非常简单的表达式,例如“true”或“1 == 1”,没有调用子shell。所以 return 表现得像 ~normal/expected~。

  2. 对于不太简单的表达式,例如,变量扩展并与某物进行比较,则 return 的行为类似于 break;

简单(无子shell)示例:

$ rtest () { if true; then echo one; return 2; echo two; fi; echo not simple; return 7; }
$ rtest
one
$ echo $?
2

$ rtest () { if [[ 1 == 1 ]] ; then echo one; return 2; echo two; fi; echo not simple; return 7; }
$ rtest
one
$ echo $?
2

$ rtest () { if [[ 1 =~ 1 ]] ; then echo one; return 2; echo two; fi; echo not simple; return 7; }
$ rtest
one
$ echo $?
2

$ rtest () { if $DO ; then echo one; return 2; echo two; else echo three; return 3; fi; echo not simple; return 7; }
$ rtest
one
$ echo $?
2

$ rtest () { if [[ $DO ]]; then echo one; return 2; echo two; else echo three; return 3; fi; echo not simple; return 7; }
$ rtest
three
$ echo $?
3

$ rtest () { if [[ $DO == 1 ]] ; then echo one; return 2; echo two; else echo three; return 3; echo four; fi; echo not simple; return 7; }
$ rtest; echo $?
one
2
$ DO=1; rtest; echo $?
one
2
$ DO=0; rtest; echo $?
three
3

表达式不简单,假设 subshel​​l 被调用,return 行为类似于 break;

不简单(子shell)示例...=~[[ ]]内:

$ rtest () { if [[ $DO =~ 1 ]] ; then echo one; return 2; echo two; fi; echo not simple; return 7; }
$ rtest
not simple
$ echo $?
7

【讨论】:

    【解决方案2】:

    如果你在函数内部return,该函数将停止执行但整个程序不会退出。

    如果你在函数内部exit,整个程序会退出。

    您不能在 Bash 脚本的主体中使用 return。您只能在函数或源脚本中使用return


    例如:

    #!/usr/bin/env bash
    
    function doSomething {
        echo "a"
        return
        echo "b"  # this will not execute because it is after 'return'
    }
    
    function doSomethingElse {
        echo "d"
        exit 0
        echo "e"  # this will not execute because the program has exited
    }
    
    doSomething
    echo "c"
    doSomethingElse
    echo "f"  # this will not execute because the program exited in 'doSomethingElse'
    

    运行上面的代码会输出:

    a
    c
    d
    

    【讨论】:

      【解决方案3】:

      问题是:子shell 是一个单独的进程。 它真的没有办法对父 shell 说:“我因为返回而退出”

      退出状态中没有这种东西,这是父shell唯一得到的东西。

      【讨论】:

        【解决方案4】:

        但是return 应该终止函数调用,而不是子shell。 exit 旨在终止(子)shell。我认为,这是一些未记录的错误/功能。

        • echo | return 在命令行中输入会出错。没错 - return 应该在函数中。
        • f(){ echo|return; } 在 Bash 中被接受,Dash 被接受,但 return 不会终止函数调用。

        如果return 终止子shell,它将在函数之外工作。所以,结论是:return 终止函数中的子shell,这很奇怪。

        【讨论】:

        • 这是一个支持结论的演示:function foo { echo start function; ( echo start subshell; return; echo end subshell); echo end function; }
        • 这似乎是一个很好的解释。 if 或 while 语句中的简单表达式不会导致子 shell 运行,因此 return 将表现为~正常/预期~。更复杂的表达式(例如,在表达式中使用变量)将导致子shell,因此 return 看起来就像一个中断;。
        【解决方案5】:

        date | while ... 场景中,由于管道的存在,while 循环在子shell 中执行。因此,return 语句会中断循环并且 subshel​​l 结束,让您的函数继续执行。

        您必须重构代码以删除管道,以便不创建子外壳:

        dostuff() {
            # redirect from a process substitution instead of a pipeline
            while true; do
                echo returning 0
                return 0
                echo really-notreached
            done < <(date)
        
            echo notreached
            return 3
        }
        

        【讨论】:

          猜你喜欢
          • 2015-12-04
          • 2018-03-07
          • 2019-06-08
          • 1970-01-01
          • 2017-12-04
          • 2014-04-05
          • 2017-12-24
          • 1970-01-01
          • 2021-09-22
          相关资源
          最近更新 更多