繁体   English   中英

使用set -e时,bash单行条件失败

[英]bash one-line conditional fails when using set -e

我开始在bash脚本中使用set -e,发现条件表达式的简短形式破坏了脚本的执行。

例如,以下行应检查$ var是否为空:

[ -z "$var" ] && die "result is empty"

但是当$ var具有非零长度时,会导致脚本无提示退出。

我在很多地方都使用了这种形式的条件表达式...

我应该怎么做才能使其正常运行? 用“ if”构造重写所有内容(这很丑)? 还是放弃“ set -e”?

编辑:每个人都在要求代码。 这是完整的[非]工作示例:

#!/bin/bash
set -e

function check_me()
{
    ws="smth"
    [ -z "$ws" ] && echo " fail" && exit 1
}

echo "checking wrong thing"
check_me
echo "check finished"

我希望它在函数调用之前和之后都打印回显。 但是它在check_me函数中无提示地失败了。 输出为:

checking wrong thing

采用

[ -n "$var" ] || die "result is empty"

这样,如果$var为非空值,则整个语句的返回值为true,因此不会触发ERR陷阱。

您应该编写脚本,以使任何命令都不会以非零状态退出。

在您的命令中[ -z "$var" ]可以为true,在这种情况下,您调用die ,或者为false,在这种情况下, -e就是这样。

如您所说,可以使用if编写它,也可以使用如下代码:

[ -z "$var" ] && die "result is empty" || true

我会建议if

恐怕您将不得不重写所有内容,以免发生错误的陈述。

set -e的定义很明确:

-e如果简单命令(请参见上面的SHELL GRAMMAR)以非零状态退出,则立即退出。 如果失败的命令紧随一段时间或直到关键字,if语句中测试的一部分,&&或||的一部分之后的命令列表的一部分,则外壳程序不会退出。 列表,或者命令的返回值通过!反转。 退出外壳之前,将执行ERR上的陷阱(如果已设置)。

您正在使用Bash的“优化”系统:因为错误的语句将导致AND( && )语句永远不为真,因此bash知道不必执行该行的第二部分。 但是,这是对系统的巧妙“滥用”,不是预期的行为,因此与set -e不兼容。 您将必须重写所有内容,因此if使用s则使用正确的内容。

bash帮助尚不清楚的是,只有&&||最后一条语句 链会导致在set -e下退出。 如果bar返回false,则foo && bar将退出,但如果foo返回false,则不会退出。

因此,您的脚本应该可以工作...但是不能。 为什么?

这不是因为-z测试失败。 这是因为失败使函数 返回非零状态

#!/bin/bash
set -e

function check_me()
{
    ws="smth"
    [ -z "$ws" ] && echo " fail" && exit 1
    # The line above fails, setting $? to 1
    # The function now returns, returning 1!
}

echo "checking wrong thing"
check_me   # function returns 1, causing exit here
echo "check finished"

因此,有多种方法可以解决此问题。 您可以在函数内部的条件check_me或调用check_me的行中添加||true 但是,正如其他人指出的那样,使用||true有其自身的问题。

在此特定场景中, check_me的所需后置条件是“此内容有效或脚本已退出”,直接要做的就是这样写它,即[[ -n "$ws" ]] || die "whatever" [[ -n "$ws" ]] || die "whatever"

但是,通常只要不将条件作为函数中的最后一项,使用&&条件实际上通常可以与set -e配合使用。 您需要添加一个明确的truereturn 0 ,甚至:作为一个语句之后这样的条件,除非你打算的功能,当条件不满足返回false。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM