`return 0` 是否等于 `true` (在 shell 环境的源脚本中)?

`return 0` 是否等于 `true` (在 shell 环境的源脚本中)?
  • 我正在开发一个高度可移植的脚本,用户应将其来源到他们的 shell,这迫使我使用 POSIX 脚本。

  • 脚本中有许多有用的函数,其中之一很特殊,因为它返回调用函数的状态truefalse


return 0现在,我曾经在这样的情况下使用过。但它似乎更具可读性truefalseforreturn 1也分别有效。

问题是这些是否有效非常同样的方式或者是否有差异。谢谢。

答案1

true是可移植的,但本身不会返回。return true不便于携带,也不能可靠地工作。

如果你有这样的函数:

f() {
    true
}

那么是的,它将以退出状态为零的方式从函数返回。当从末尾掉下来时,返回最后一个命令的退出状态作为函数的退出状态。

但当然,这不会以真实状态返回,因为true中间本身不会影响控制流。

g() {
    # silly example condition
    if [ 1 = 1 ]; then
        true
    fi
    echo something else
    false
}

但你可以添加一个明确的返回,return带参数也使用最后一个命令的退出状态:

特殊参数'?'的值应设置为 n(无符号十进制整数),或者如果未指定 n,则设置为最后执行的命令的退出状态。如果 n 不是无符号十进制整数,或者大于 255,则结果未指定。

h() {
    # silly example condition
    if [ 1 = 1 ]; then
        true
        return
    fi
    echo something else
    false
}

现在,如果您尝试return true,它可能会在某些 shell 中执行您想要的操作,但最终可能不会。至少在 zsh 中,它似乎将参数视为算术表达式,因此return true将使用变量的值true,如果未设置,则默认为零。

% i() { return 1+1; }
% i; echo $?
2

% unset true
% j() { return true; }
% j; echo $?
0

% true=123
% j; echo $?
123

如果您可以安排true将 始终设置为0和 并false设置为1,并且相信脚本库的用户不会弄乱这些,那么您可以在 zsh 或标准shell 中使用return true和。我不建议使用这些名称,但也许可以使用类似或的名称。return falsereturn "$true"return "$false"true_return_valuefalse_return_value

否则,您可以在标准 shell 中使用true; returnand false; return,但我不确定这是否比return 0and更具可读性return 1。无论如何,shell 程序员都应该熟悉真实返回值为零这一事实。

答案2

truefalse不是可移植的有效布尔值。

例如,一个简单的 shell 脚本

f()
{
  return true
}

f && echo whee

如果我们在不同的 shell 下运行:

$ sh x
return: Illegal number: 'true'
$ bash x
x: line 3: return: true: numeric argument required
$ ksh93 x
whee
$ zsh x
whee
$ ksh x
x[6]: true: bad number

(最后一个shell是pdksh 5.2.14)

不过return 0是便携的

$ cat x
f()
{
  return 0
}

f && echo whee

$ sh x
whee
$ bash x
whee
$ ksh93 x
whee
$ zsh x
whee
$ ksh x
whee

如果 0 被视为 true,我们还可以看到返回,因此有效&&

现在我们可以作弊了..

f()
{
  true
}

它的作用是调用true命令...,然后使用这样一个事实:没有显式的函数的返回码return是最后一个命令运行的返回值。

所以虽然这会工作它不那么可读,因为没有明确的行为return,并且您依赖于隐式行为。

答案3

这是POSIX 对此有什么说法:

  • return 实用程序应使 shell 停止执行当前函数或点脚本。如果 shell 当前未执行函数或点脚本,则结果未指定。
  • 特殊参数'?'的值应设置为 n(无符号十进制整数),或者如果未指定 n,则设置为最后执行的命令的退出状态。如果 n 不是无符号十进制整数,或者大于 255,则结果未指定。当在 trap 操作中执行 return 时,最后一个命令被认为是紧接在 trap 操作之前执行的命令。

所以:

  • 您可以使用return从源脚本(点脚本)返回,而不仅仅是函数。

  • 您可以传递 0 或 1 个参数(没有选项,--甚至可能不被接受),但它必须是一个无符号十进制整数(0, 1, 2... 不是true, 0x1, -1, +1, 不清楚并且实际上不可移植,010可以将其视为八进制数,而不是十进制数,并且实际上就像 zsh 中的情况一样sh 仿真)

  • 因为return不带参数返回上一个命令的状态,所以{ true; return; }可以是返回成功退出状态的一种方法。请注意,虽然这{ false; return; }会返回非零(失败)退出状态,但未false指定返回哪个退出状态(实际上,我从未见过任何使用除 之外的任何实现1),并且false可能会退出 shell(或子 shell) ) 如果该errexit选项已启用(可以使用 解决{ false || return; })。目前尚不清楚是否return $(true)return $(false)应该起作用。实际上,它不在 dash 或 mksh 中,因此不可移植。

  • 目前尚不清楚是什么shell 当前没有执行函数或点脚本确切地说。有些人将其解释为return从子 shell 中使用,即使该子 shell 是从函数或点脚本中运行的,或者函数体(如f() (return 1))未指定。但在实践中,我发现return在这些情况下,行为就像exit.它从当前子 shell 退出/返回,但不从封闭的函数/点脚本退出/返回。

    无论如何,要从函数/点脚本返回,如果该子 shell 不是函数/点脚本中的最后一个命令,则必须在子 shell 外部完成,请记住,子 shell 的构成因 shell 而异。例如在:

    f() {
      cmd | {
        IFS= -r read var || return
        echo whatever
        cat
      }
      echo Here
    }
    

    return将从 ksh 或 zsh 中的函数返回,但不会在 bash(除非设置了该选项)或 dash、mksh 中返回lastpipe,因为在这些中,所有管道组件,甚至是子 shell 中的最后一次运行(POSIX 允许)。所以你需要用类似的方法来解决它:

    f() {
      cmd | {
        IFS= -r read var || return
        echo whatever
        cat
        true
      } || return
      echo Here
    }
    

    强制使用子 shell 并exit在其中使用将使其明显符合 POSIX 并在 shell 之间保持一致的行为(并且更清楚的是$var变量分配 byread可能无法在管道中幸存):

    f() {
      cmd | (
        IFS= -r read var || exit
        echo whatever
        cat
        true
      ) || return
      echo Here
    }
    

    (在所有这些return/中,exit将返回失败退出状态read;您可以更改为exit 1/return 1以给出特定的失败退出状态值)

  • ! return请注意或的行为! return 1是不可移植的(对于 没有那么有用,但如果可移植 for来从失败退出状态的循环中中断return会更有用)。! break

在任何情况下,truefalse命令都不会导致封闭的函数/点脚本返回,除非已经注意到errexit设置选项的特殊情况(并且其效果不会以某种方式取消),在这种情况下会失败命令包括false导致 shell 进程退出(不一定/仅包含封闭函数/点脚本),它们是普通命令,通常是内置的,但不是特殊的内置函数更不用说与//相反的控制流return运算breakcontinue

为了使代码更清晰,您可以选择为成功退出状态和失败退出状态定义变量,例如:

ok=0 true=0 success=0 yes=0 on=0
failure=1 false=1 no=1 off=1

并使用return "$true"orreturn "$false"或 与 相同exit,在 zsh 中可以简化为return $trueor 甚至return true

但请注意,在算术表达式中,含义是相反的,0 表示 false,其他值表示 true,就像在 C 中一样。因此,这些变量的值while (( true ))(在类似 Korn 的 shell 中)将无法按预期工作,因此您可能更愿意命名这些变量变量status_okstatus_failure而不是ok/ failure

相关内容