防止grep在不匹配的情况下退出


29

该脚本不回显“ after”:

#!/bin/bash -e

echo "before"

echo "anything" | grep e # it would if I searched for 'y' instead

echo "after"
exit

如果我删除了-eshebang行上的选项,也可以,但是我希望保留它,以便在出现错误时脚本停止。我不认为grep发现没有匹配项是错误。如何防止它过分退出?


这只是一个考虑因素。也许应该重新考虑一下此脚本的逻辑。如果查找字符串并不重要,为什么要搜索它?grep的定义是根据字符串的存在或不存在来做出决定。如果您不在乎这两种方式,那么这并不重要。同样,这似乎-e是您必须在意的前提:如此之多,以至于任何问题都是灾难性的。
安德鲁·法兰加

2
@AndrewFalanga我不管用哪种方式,因为我实际上正在分析其内容var=$(complex command | grep complex_pattern)可能为null(在这种情况下,我的程序不应终止)。这只是使问题发生的精简脚本。这里的逻辑中没有形而上学的黑洞,对吗?;)
iago-lito

现在知道要捕获输出确实可以澄清一些事情。如前所述,这让我感到困惑。
安德鲁·法兰加

Answers:


33
echo "anything" | grep e || true

说明:

$ echo "anything" | grep e
### error
$ echo $?
1
$ echo "anything" | grep e || true
### no error
$ echo $?
0
### DopeGhoti's "no-op" version
### (Potentially avoids spawning a process, if `true` is not a builtin):
$ echo "anything" | grep e || :
### no error
$ echo $?
0

“ ||” 表示“或”。如果命令的第一部分“失败”(表示“ grep e”返回非零退出代码),则“ ||”之后的部分 被执行,成功并返回零作为退出代码(true始终返回零)。


3
不会旋转的相同版本的稍短版本/bin/true是:( command || :因此,在您的情况下为set -e; grep 'needle' haystack || :)。
DopeGhoti

1
@DopeGhoti true是某些shell中的内置组件(至少bash 4.3在RHEL上)
iruvar

3
无效,因为如果第一个命令失败,它将隐藏错误。如果管道中的第一个命令失败,则正确的解决方案应返回非零值。
索林

11

安全和可选地 grep发送消息的可靠方法:

echo something | grep e || [[ $? == 1 ]] ## print 'something', $? is 0
echo something | grep x || [[ $? == 1 ]] ## no output, $? is 0
echo something | grep --wrong-arg e || [[ $? == 1 ]] ## stderr output, $? is 1

根据posix手册,退出代码1表示未选择任何行,> 1表示错误。


1
这应该是可以接受的答案,因为如果grep找不到任何东西,它只会抑制警告退出代码(1),但是会传递真实错误(退出代码> 1)。这里的其他解决方案总是抑制真正的错误,这通常是不好的。
哈罗德·芬奇

7

另一种选择是将另一条命令添加到管道中-一条不会失败的命令:

echo "anything" | grep e | cat

因为 cat现在是管道中的最后一条命令,所以将使用而cat不是的退出状态grep来确定管道是否失败。



3

#!/bin/bash -e

echo "before"

echo "anything" | grep e || : # it would if I searched for 'y' instead

echo "after"
exit

说明

set -e 要么 set -o errexit

如果管道(可能由一个简单命令组成),列表复合命令(请参见SHELL GRAMMAR上文)以非零状态退出,则立即退出。如果失败的命令是紧接在whileuntil关键字之后的命令列表的一部分,紧跟在ifelif保留字之后的测试的一部分,在&&||列表中执行的任何命令的一部分(除了final之后 的命令),则外壳程序不会退出&&或之后||,管道中的命令,但最后一个管道,或者命令的返回值与!。如果除子Shell之外的复合命令由于-e被忽略而失败而返回非零状态,则Shell不会退出。 on上的陷阱ERR(如果已设置)在外壳退出之前执行。该选项分别适用于Shell环境和每个子Shell环境(请参见COMMAND EXECUTION ENVIRONMENT上文),并且可能导致子Shell在执行子Shell中的所有命令之前退出。

另外,:是Bash中的no-effect命令。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.