我正在开发一个高度可移植的脚本,用户应将其来源到他们的 shell,这迫使我使用 POSIX 脚本。
脚本中有许多有用的函数,其中之一很特殊,因为它返回调用函数的状态
true
。false
return 0
现在,我曾经在这样的情况下使用过。但它似乎更具可读性true
或false
forreturn 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 false
return "$true"
return "$false"
true_return_value
false_return_value
否则,您可以在标准 shell 中使用true; return
and false; return
,但我不确定这是否比return 0
and更具可读性return 1
。无论如何,shell 程序员都应该熟悉真实返回值为零这一事实。
答案2
true
和false
不是可移植的有效布尔值。
例如,一个简单的 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
- 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
在任何情况下,true
和false
命令都不会导致封闭的函数/点脚本返回,除非已经注意到errexit
设置选项的特殊情况(并且其效果不会以某种方式取消),在这种情况下会失败命令包括false
导致 shell 进程退出(不一定/仅包含封闭函数/点脚本),它们是普通命令,通常是内置的,但不是特殊的内置函数更不用说与//相反的控制流return
运算break
符continue
了
为了使代码更清晰,您可以选择为成功退出状态和失败退出状态定义变量,例如:
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 $true
or 甚至return true
但请注意,在算术表达式中,含义是相反的,0 表示 false,其他值表示 true,就像在 C 中一样。因此,这些变量的值while (( true ))
(在类似 Korn 的 shell 中)将无法按预期工作,因此您可能更愿意命名这些变量变量status_ok
,status_failure
而不是ok
/ failure
。