当输入不匹配时,防止grep返回错误

时间:2011-07-01 16:13:15

标签: bash grep

我想在bash脚本中编写一段代码,用于检查程序是否已在运行。 我有以下内容,以搜索栏是否正在运行

 foo=`ps -ef | grep bar | grep -v grep`

 grep -v grep

部分是为了确保在ps结果中不考虑“grep bar”

当bar未运行时,foo正确为空。但我的问题在于脚本已经

 set -e

是一个标志,如果某个命令返回错误,则终止脚本。 事实证明,当bar未运行时,“grep -v grep”与任何内容都不匹配,grep会返回错误。我尝试使用-q或-s但无济于事。

有没有解决方法? THX

6 个答案:

答案 0 :(得分:61)

不确定

ps -ef | grep bar | { grep -v grep || true; }

甚至:

ps -ef | grep bar | grep -v grep | cat

答案 1 :(得分:15)

避免grep -v grep的好方法是:

ps -ef | grep '[b]ar'

该正则表达式仅匹配字符串“bar”。但是在ps输出中,字符串“bar”不会出现在grep进程中。


在我了解pgrep之前的几天,我写了这个函数来自动执行上面的命令:

psg () { 
    local -a patterns=()
    (( $# == 0 )) && set -- $USER
    for arg do
        patterns+=("-e" "[${arg:0:1}]${arg:1}")
    done
    ps -ef | grep "${patterns[@]}"
}

然后,

psg foo bar

变成

ps -ef | grep -e '[f]oo' -e '[b]ar'

答案 2 :(得分:10)

为什么要求ps提供-ef的大量输出,如果你只是要扔掉99%的输出? ps尤其是GNU版本是瑞士军刀,功能强大。试试这个:

ps -C bar -o pid= 1>/dev/null

我在这里指定-o pid=只是因为,但事实上它是毫无意义的,因为我们无论如何都扔掉了所有的stdout。但是,如果您想知道实际运行的PID,那将非常有用。

如果ps无法匹配任何内容,

-C将自动返回非零存在状态,如果匹配则为零。所以你可以简单地说这个

ps -C bar 1>/dev/null && echo bar running || echo bar not running

或者

if ps -C bar 1>/dev/null ; then
    echo bar running
else
    echo bar not running
fi

这不是更简单吗?不需要grep,不需要两次甚至一次。

答案 3 :(得分:7)

简短回答

ps -ef | grep bar | { grep -v grep || test $? = 1; }

如果您使用 set -e

如果您使用bash的 pipefail 选项(set -o pipefail),请务必将异常处理(||test)应用于每个grep管道

ps -ef | { grep bar || test $? = 1; } | { grep -v grep || test $? = 1; }

shell脚本中,我建议您使用“catch-1-grep”(c1grep)实用程序函数:

c1grep() { grep "$@" || test $? = 1; }

解释

grep的退出状态为0,1或2:[1]

  • 0表示已选择一行
  • 1表示未选择任何行
  • 2表示发生了错误

grep如果被信号中断(例如,130用于SIGINT),也可以返回其他代码。

由于我们只想忽略退出状态1,因此我们使用test来取消特定的退出状态。

  • 如果grep返回0,则test未运行。
  • 如果grep返回1,则会运行test并返回0
  • 如果grep返回任何其他值,则会运行test并返回1

在最后一种情况下,由于set -eset -o pipefail,脚本会立即退出。但是,如果您根本不关心grep错误,您当然可以写

ps -ef | grep bar | { grep -v grep || true; }

根据Sean的建议。

[shell]中的[附加]用法

在shell脚本中,如果你经常使用grep,我建议你定义一个效用函数:

# "catch exit status 1" grep wrapper
c1grep() { grep "$@" || test $? = 1; }

这样你的烟斗就会变短了。再简单,不会丢失set -eset -o pipefail的功能:

ps -ef | c1grep bar | c1grep -v grep

供参考:

  • 我打电话给它c1grep强调它只是捕捉退出状态1,没有别的。
  • 我本可以调用函数grep而不是grep() { env grep "$@" ...; }),但我更喜欢一个不那么混乱且更明确的名称c1grep

[1] grep联页>

答案 4 :(得分:1)

foo=`ps -ef | grep bar | grep -v grep` || true

答案 5 :(得分:1)

尝试这样做:

  

ps auxw | grep -v grep |猫

cat总是返回0并忽略grep的退出代码