shell脚本在设置e和o时无法正确运行

shell脚本在设置e和o时无法正确运行

下面的代码,当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 xtraceis -x-o errexitis -e( pipefail,来自 ksh,现在在大多数其他 shell 中都可以找到,并且很快将成为标准,在大多数 shell 中没有等效的单个字母)

errexit意味着如果未处理的命令失败,脚本将退出。pipefail意味着如果管道中有任何组件发生故障,则整个管道被视为失败(否则仅考虑最右边的组件)。

因此,echo 'x' |grep '1x' | wc -l如果这 3 个命令(echogrepwc)中的任何一个失败,该管道就会失败。

在这里,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
) 

允许失败echowc退出该脚本(请注意,这涉及一个额外的子 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)是一个非常脆弱的功能。除了最简单的脚本之外,我不建议将其用于任何其他用途,并改为手动进行错误处理。您应该问自己,如果脚本的每一行命令都失败,会发生什么,就像在任何编程语言中所做的那样。

相关内容