我开始在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
答案 0 :(得分:5)
使用
[ -n "$var" ] || die "result is empty"
这样,如果$var
非空,则整个语句的返回值为true,因此不会触发ERR
陷阱。
答案 1 :(得分:2)
您应编写脚本,以便任何命令都不会以非零状态退出。
在你的命令中[ -z "$var" ]
可以是真的,在这种情况下你可以调用die
,或者假,-e
就是这样。
如你所说,用if
写,或者使用类似的东西:
[ -z "$var" ] && die "result is empty" || true
我建议if
。
答案 2 :(得分:2)
我担心你必须重写所有内容,所以不会发生虚假陈述。
set -e
的定义很明确:
-e如果一个简单的命令(参见上面的SHELL GRAMMAR)以非零状态退出,则立即退出。如果失败的命令是紧跟在while或者直到关键字之后的命令列表的一部分,在if语句中是测试的一部分,并且&&amp ;;的一部分,则shell不会退出。或||列表,或者命令的返回值是否被反转! ERR上的陷阱(如果已设置)将在shell退出之前执行。
您正在使用Bash的“优化”系统:因为false语句会导致AND(&&
)语句永远不会成立,bash知道它不必执行该行的第二部分。但是,这是对系统的巧妙“滥用”,而不是预期的行为,因此与set -e
不兼容。您必须重写所有内容,以便使用正确的if
s。
答案 3 :(得分:0)
bash帮助不是很清楚,只有&&
或||
链中的 last 语句会导致{{1}下的退出}}。 set -e
会在foo && bar
返回false时退出,但如果bar
返回false则不会退出。
所以你的脚本应该工作......但事实并非如此。为什么呢?
这不是因为foo
测试失败。这是因为失败使功能 返回非零状态:
-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"
添加到函数内的条件,或调用||true
的行。但正如其他人所指出的,使用check_me
有其自身的问题。
在这个特定的场景中,||true
所需的后置条件是“这个东西是有效的还是脚本已退出”,直截了当的做法就是这样写,即check_me
但是使用[[ -n "$ws" ]] || die "whatever"
条件实际上通常可以正常使用&&
,只要你不使用这样的条件作为函数中的最后一件事。您需要在此类条件之后添加显式set -e
或true
或甚至return 0
作为语句,除非您打算该函数在条件时返回false失败。