我想用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有关吗?
您只需检查grep
的返回状态:
grep -q luck myfile.txt || no_luck=1
Shell实用程序使用返回状态与shell通信;他们正在沟通的不一定是错误的条件。正如grep示例所示,它可以是一个简单的布尔值。实际上,[[
builtin(及其朋友[
和test
)正是这样做的:使用状态代码返回一个布尔结果。这并没有使这些工具变得“松懈”。
set -e
忽略在||
或&&
连接器的条件或左侧执行的命令的非零状态返回,这使得可以使用set -e
。
话虽如此,-e
是一个非常生硬的工具,一般不建议在生产代码中使用它。您始终可以使用||
明确失败:
important_setup || exit 1
您的if
命令似乎包含一些拼写错误(#
之前的额外]
和缺少空格),但更一般地说,您应该明白if
的目的是运行命令并检查其退出代码。任何看起来像的东西
command
if [ $? = 0 ]; then
更紧凑和惯用语写
if command; then
在这种情况下,command
的失败退出状态不是导致set -e
终止脚本的条件(因为那时你不能在else
的脚本中使用set -e
子句!)
在这个then
和else
块都包含简单命令的特定示例中,您可以简化为速记
grep -q 'needle' haystack && handle_grep_results || handle_grep_no_results
这也表明了
command || true
当你根本不关心command
是否成功与set -e
的脚本。
(另请注意grep -q
关于grep >/dev/null
- 前者暗示-m 1
,即grep
可以关闭文件并在找到第一场比赛后立即返回成功。)