需要帮助 - 在 GNU/LINUX bash 上的 shell 脚本环境中:
我总是用set -e
.通常,我希望grep
但并不总是希望脚本在grep
退出状态1
指示未找到模式时终止执行。
我尝试解决这个问题的方法如下:
(尝试 I)
如果set +o pipefail
并用类似的东西调用 grepgrep 'p' | wc -l
那么我会得到所需的行为,直到未来的维护者启用pipefail
。另外,我喜欢启用,pipefail
所以这对我不起作用。
(尝试二)
使用sed
或awk
仅打印与模式匹配的行,然后使用wc
匹配的行来测试匹配的模式。我不喜欢这个选项,因为使用sed
togrep
似乎是解决我真正问题的方法。
(尝试 III)
这是我最不喜欢的 - 类似于:set +e; grep 'p'; set-e
任何见解/习语将不胜感激 - 谢谢。
答案1
您可以将 grep 置于if
条件中,或者如果您不关心退出状态,请添加|| true
.
示例:grep
杀死 shell
$ bash
$ set -e
$ echo $$
33913
$ grep foo /etc/motd
$ echo $$
9233
解决方案1:丢弃非零退出状态
$ bash
$ set -e
$ echo $$
34074
$ grep foo /etc/motd || true
$ echo $$
34074
解决方案 2:显式测试退出状态
$ if ! grep foo /etc/motd; then echo not found; fi
not found
$ echo $$
34074
从 bash 手册页讨论set -e
:
如果失败的命令是紧跟在命令列表中的一部分,则 shell 不会退出尽管或者直到 关键字,测试的一部分如果或者埃利夫保留字,任何命令中执行的一部分 &&或者│列出最后一个命令之后的命令除外&&或者│,管道中除最后一个命令之外的任何命令,或者命令的返回值与!。
答案2
要禁用命令失败时的效果errexit
,正如其他人所说,将该命令用作条件语句的一部分就足够了,无论是在if
/elif
和then
、或while
/until
和do
或 后跟&&
或||
逻辑运算符之间。
errexit
在不更改退出状态的情况下禁用该效果的规范习惯用法是:
cmd && true
那仍然返回虚假的ifcmd
失败但不退出 shell。
但通常情况下,您想要的只是忽略失败及其errexit
影响。
因此,更规范的方法是:
cmd || true
哪个返回特鲁伊无论cmd
成功与否。
grep
回报特鲁伊如果任何输入中至少有一行匹配并且没有发生错误并且虚假的否则。
它通常用于:
if grep -q pattern file; then
echo at least one line of file matched the pattern
do-something
fi
如果您想要的只是 if any 的输出grep
,而不关心是否没有匹配,您可以忽略 的grep
退出状态:
grep pattern file || true
但你不会抓住错误例如当file
无法打开或正则表达式中存在语法错误或grep
无法写入其输出时。
grep
1
对于不匹配和错误,将使用退出状态,如果未找到,2
shell 可能会设置$?
为 127 ,如果被杀死,则 shell 可能会设置为大于 128 的数字。grep
因此,您应该能够根据 的值来消除不匹配和错误之间的歧义$?
,并且errexit
仅使用以下内容来触发错误:
grep pattern file || [ "$?" -eq 1 ]
哪个返回特鲁伊如果grep
成功或者没有匹配,但是会因为失败而退出errexit
([
除了不匹配之外的错误)$?
。1
不过,通常建议进行适当的错误处理,而不是依赖于非常不稳定的错误set -o errexit
(又名set -e
)。如果您需要区分 的不同故障模式grep
,您可以这样做:
die() { [ "$#" -eq 0 ] || printf>&2 '%s\n' "$@"; exit 1; }
grep pattern file
case $? in
(0) echo OK, match;;
(1) echo OK, no match;;
(*) handle-error; die;;
esac
答案3
pipefail
您也可以使用子 shell暂时禁用或忽略该设置。
( set +o pipefail ; grep 'p' ) | wc -l
或者
( grep 'p' || true ) | wc -l
另外,请注意|
比 结合得更紧密||
,因此第二种情况中的括号是必需的。
答案4
关心退出状态时的另一个选择:
FOUND=$(grep whatever here) || true
if [ -z $FOUND ]; then
echo "not found"
else
echo "found"
fi