我有一个带有头部#!/bin/bash -e
的Bash Shell脚本。
当我运行脚本时,grep
命令运行后会被中断,但是当我删除参数-e
后,脚本可以正常运行。 参数-e
的含义是什么?
-e
选项的意思是“如果任何管道以非零('错误')退出状态结束,则立即终止脚本”。由于当grep
没有找到任何匹配时,它会返回1
的退出状态,因此即使没有真正的“错误”,它也可能导致-e
终止脚本。-e
选项,但也要有一个grep
命令,该命令可能有效地找不到任何匹配项,您可以在grep
命令后附加|| :
。这意味着“或者,如果grep
命令返回非零退出状态,则运行:
(什么也不做)”; 因此,净效果是禁用-e
选项对于grep
命令。所以:grep PATTERN FILE... || :
编辑备注: 以上方法会忽略每一个错误: 如果grep
返回1
,表示找不到匹配的内容,则会被忽略;如果grep
返回2
,表示出现了错误,则也会被忽略;如果grep
不在路径中(因此Bash返回127
),则同样被忽略 - 等等。因此,最好使用一个检查结果代码并在其它情况下重新发出错误的命令,而不是:
。例如:
grep PATTERN FILE || (( $? == 1 ))
但这样会破坏退出状态;通常,当一个失败的命令以-e
终止Bash脚本时,脚本将返回命令的退出状态,但在上面的示例中,脚本只会返回1
。如果我们关心这个问题(且只有这种情况下),我们可以编写如下内容来解决它:
grep PATTERN FILE || exit_code=$?
if (( exit_code > 1 )) ; then
exit $exit_code
fi
此时,最好创建一个shell函数来帮助我们处理:
(第一行由dsummersl的评论提供)
function grep_no_match_ok () {
local exit_code
grep "$@" || exit_code=$?
return $(( exit_code == 1 ? 0 : exit_code ))
}
return
而不是exit
;我们将让-e
在适当时退出处理);这样,我们就可以只写:)grep_no_match_ok PATTERN FILE # won't kill script if no matches are found
事实上,由于我们很可能希望在此脚本中使用此函数来处理grep
的所有出现情况,因此我们实际上可以将该函数命名为grep
:
function grep () {
local exit_code
command grep "$@" || exit_code=$?
return $(( exit_code == 1 ? 0 : exit_code ))
}
grep PATTERN FILE # won't kill script if no matches are found
请注意在其自身主体内使用command
来绕过shell函数的使用。我们希望该函数调用常规程序grep
,而不是无限递归。
grep XXX FILE || exitcode=$?
。超级方便! - dsummersl从详细手册中得知:
除了单字符shell命令行选项(参见Set内置命令)之外,还有一些多字符选项可供使用。
然后再看一下set
命令的说明:
-e
如果管道(参见Pipelines)失败,则立即退出,管道可以由单个简单命令(参见Simple Commands)、括在圆括号中的子shell命令(参见Command Grouping),或由花括号包含的命令列表中执行的一个命令组成(参见Command Grouping)。返回非零状态。
因此,当您使用bash -e
时,如果脚本中的任何命令失败(即返回非零退出状态),整个脚本将立即失败。所以您的grep
未匹配到结果,导致返回非零值,而运行bash时指定-e
选项,这就关闭了整个脚本。
set
命令,但我想在手册中看到它。我一直在想为什么在 man bash
中没有看到它,原来是我直接跳过了列出的选项,错过了其中的一段话,它说:“在 set 内置命令的描述中记录的所有单字符 shell 选项,包括 -o,在调用 shell 时都可以用作选项。” 全部都在那里! - Nagev
-e
选项 (http://linux.die.net/man/1/bash),所以在这种情况下到底发生了什么? :( - user166390