如何在set -e上下文中运行flakey命令?

问题描述 投票:0回答:2

我想用set -e保护我的大部分bash脚本,以便在脚本处理过程中检测到错误时提前和大声失败。但是,我仍然希望能够运行一些实际上预期会失败的命令,例如使用grep来评估某些文件内容的存在/不存在,这些文件内容用于指示脚本其余部分的控制流。如何在grep上下文中运行set -e,以便A)grep被允许失败并且B)grep的存在状态被记录以供脚本的其余部分访问?

在普通的POSIX sh中,我会做类似的事情:

grep 'needle' haystack >/dev/null
if [ "$?" -eq 0 ]; then
    handle_grep_results
else
    handle_grep_no_results
fi

但是,当在本节之前指定set -e时,只要grep找不到针,脚本就会提前退出。解决这个问题的一种方法是暂时禁用set +e的保护,然后在该部分之后重新启用它们,但如果有意义的话,我宁愿保留保护措施。这可能与bash有关吗?

bash error-handling
2个回答
1
投票

您只需检查grep的返回状态:

grep -q luck myfile.txt || no_luck=1

Shell实用程序使用返回状态与shell通信;他们正在沟通的不一定是错误的条件。正如grep示例所示,它可以是一个简单的布尔值。实际上,[[ builtin(及其朋友[test)正是这样做的:使用状态代码返回一个布尔结果。这并没有使这些工具变得“松懈”。

set -e忽略在||&&连接器的条件或左侧执行的命令的非零状态返回,这使得可以使用set -e

话虽如此,-e是一个非常生硬的工具,一般不建议在生产代码中使用它。您始终可以使用||明确失败:

important_setup || exit 1

1
投票

您的if命令似乎包含一些拼写错误(#之前的额外]和缺少空格),但更一般地说,您应该明白if的目的是运行命令并检查其退出代码。任何看起来像的东西

command
if [ $? = 0 ]; then

更紧凑和惯用语写

if command; then

在这种情况下,command的失败退出状态不是导致set -e终止脚本的条件(因为那时你不能在else的脚本中使用set -e子句!)

在这个thenelse块都包含简单命令的特定示例中,您可以简化为速记

grep -q 'needle' haystack && handle_grep_results || handle_grep_no_results

这也表明了

command || true

当你根本不关心command是否成功与set -e的脚本。

(另请注意grep -q关于grep >/dev/null - 前者暗示-m 1,即grep可以关闭文件并在找到第一场比赛后立即返回成功。)

© www.soinside.com 2019 - 2024. All rights reserved.