下面的代码,当e和o设置采样时间时,最后一行不运行,为什么?
set -x
set -e
set -o pipefail
add=$(echo 'x' |grep '1x' | wc -l)
echo $add
echo '1'
答案1
不要混合使用单字母选项和-o option
,而是对所有内容使用长选项名称,这样会更清晰:
set -o xtrace -o errexit -o pipefail
其中-o xtrace
is -x
、-o errexit
is -e
( pipefail
,来自 ksh,现在在大多数其他 shell 中都可以找到,并且很快将成为标准,在大多数 shell 中没有等效的单个字母)
errexit
意味着如果未处理的命令失败,脚本将退出。pipefail
意味着如果管道中有任何组件发生故障,则整个管道被视为失败(否则仅考虑最右边的组件)。
因此,echo 'x' |grep '1x' | wc -l
如果这 3 个命令(echo
、grep
和wc
)中的任何一个失败,该管道就会失败。
在这里,grep
将无法找到1x
的输出中包含的行echo
,因此会报告失败。由于,这将退出以相同的失败退出状态errexit
运行的子 shell 。$(...)
结果var=$(...)
赋值也会导致失败,运行脚本的 shell 也会退出。
注意这样grep | wc -l
写比较好grep -c
。
如果你想避免 的影响errexit
,可以处理该错误。
那可能是:
var=$(echo x | grep -c 1x || : no match should not be a fatal error)
这里因为在|| another command
管道之后,故障被认为是由 shell 手动处理的,所以errexit
不适用。这里的命令:
没有成功执行任何操作(true
除了它接受不执行任何操作的参数之外)。
这是正在处理的管道错误。您还可以单独处理错误grep
:
var=$(
echo x | {
grep 1x || : no match should not be a fatal error
} | wc -l
)
允许失败echo
或wc
退出该脚本(请注意,这涉及一个额外的子 shell 来运行该脚本grep || :
)。
或者处理赋值失败:
var=$(echo x | grep -c 1x) || : no match should not be a fatal error
请注意,是否在子 shell 内禁用errexit
取决于 shell 及其版本。例如,某些 shell 将输出x
,而另一些 shell 将输出空行sh -ec 'v=$(false; echo x) || true; echo "$v"'
。
errexit
(又名set -e
)是一个非常脆弱的功能。除了最简单的脚本之外,我不建议将其用于任何其他用途,并改为手动进行错误处理。您应该问自己,如果脚本的每一行命令都失败,会发生什么,就像在任何编程语言中所做的那样。