[英]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
配合使用。 您需要添加一个明确的true
或return 0
,甚至:
作为一个语句之后这样的条件,除非你打算的功能,当条件不满足返回false。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.