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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6550484/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 20:43:06  来源:igfitidea点击:

Prevent grep returning an error when input doesn't match

bashgrep

提问by George Kastrinis

I want to write in a bash script a piece of code that checks if a program is already running. I have the following in order to search whether bar is running

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

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

The

 grep -v grep

part is to ensure that the "grep bar" is not taken into account in ps results

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

When bar isn't running, foo is correctly empty. But my problem lies in the fact tha the script has

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

 set -e

which is a flag to terminate the script if some command returns an error. It turns out that when bar isn't running, "grep -v grep" doesn't match with anything and grep returns an error. I tried using -q or -s but to no avail.

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

Is there any solution to that? Thx

有什么解决办法吗?谢谢

采纳答案by Sean

Sure:

当然:

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

Or even:

甚至:

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

回答by myrdd

Short answer

简答

Write

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

if you are using set -e.

如果您正在使用set -e.

If you use bash's pipefailoption (set -o pipefail), remember to apply the exception handling (||test) to every grepin the pipeline:

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

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

In shell scriptsI suggest you to use the ”catch-1-grep“(c1grep) utility function:

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

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


Explained

解释

grep's exit status is either 0, 1 or 2: [1]

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

  • 0means a line is selected
  • 1means no lines were selected
  • 2means an error occurred
  • 0意味着选择了一条线
  • 1表示未选择任何行
  • 2表示发生错误

grepcan also return other codes if it's interrupted by a signal (e.g. 130for SIGINT).

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

Since we only want to ignore exit status 1, we use testto suppress that specific exit status.

由于我们只想忽略退出状态1,因此我们使用test抑制该特定退出状态。

  • If grepreturns 0, testis not run.
  • If grepreturns 1, testis run and returns 0.
  • If grepreturns any other value, testis run and returns 1.
  • 如果grep返回0test则不运行。
  • 如果grep返回1test则运行并返回0
  • 如果grep返回任何其他值,test则运行并返回1

In the last case, the script will exit immediately due to set -eor set -o pipefail. However, if you don't care about greperrors at all, you can of course write

在最后一种情况下,脚本将由于set -e或立即退出set -o pipefail。但是,如果你根本不在乎grep错误,你当然可以写

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

as suggested by Sean.

正如肖恩所建议的那样。



[additional] usage in shell scripts

[附加] 在 shell 脚本中的用法

In shell scripts, if you are using grepa lot, I suggest you to define an utility function:

在shell脚本中,如果你使用grep的很多,我建议你定义一个实用函数:

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

This way your pipe will get short & simple again, without losing the features of set -eand set -o pipefail:

这样,你的管道将获得短期和简单再次,不失的特点set -eset -o pipefail

ps -ef | c1grep bar | c1grep -v grep

FYI:

供参考:

  • I called it c1grepto emphasize it's simply catching exit status 1, nothing else.
  • I could have called the function grepinstead (grep() { env grep "$@" ...; }), but I prefer a less confusing and more explicit name, c1grep.
  • 我调用它是c1grep为了强调它只是捕获退出状态1,没有别的。
  • 我可以grep改为调用该函数( grep() { env grep "$@" ...; }),但我更喜欢使用一个不那么令人困惑且更明确的名称c1grep.


[additional] ps+ grep

[附加] ps+grep

So if you want to know how to avoid grep -v grepor even the | greppart of ps|grepat all, take a look at some of the other answers; but this is somewhat off-topic imho.

所以,如果你想知道如何避免grep -v grep甚至| grep部分ps|grep可言,看看一些其他的答案; 但这有点题外话恕我直言。



[1] grepmanpage

[1]grep联机帮助页

回答by glenn Hymanman

A good trick to avoid grep -v grepis this:

避免的一个好技巧grep -v grep是:

ps -ef | grep '[b]ar'

That regular expression only matches the string "bar". However in the psoutput, the string "bar" does not appear with the grep process.

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



In the days before I learned about pgrep, I wrote this function to automate the above command:

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

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

Then,

然后,

psg foo bar

turns into

变成

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

回答by sorpigal

Why ask psto provide massive amounts of output with -efif you only are going to throw away 99% of it? psand especially the GNU version is a swiss army knife of handy functionality. Try this:

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

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

I specify -o pid=here just because, but in fact it's pointless since we throw away all of stdout anyway. It would be useful if you wanted to know the actual running PID, though.

-o pid=在这里指定只是因为,但实际上它毫无意义,因为我们无论如何都扔掉了所有标准输出。不过,如果您想知道实际运行的 PID,这将很有用。

psautomatically will return with a non-zero exist status if -Cfails to match anything and with zero if it matches. So you could simply say this

ps如果-C无法匹配任何内容,则自动返回非零存在状态,如果匹配则返回零。所以你可以简单地说这个

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

Or

或者

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

Isn't that simpler? No need for grep, not twice or even once.

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

回答by DigitalRoss

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

回答by Vladyslav Savchenko

Try to make so:

尝试这样做:

ps auxw | grep -v grep | cat

ps auxw | grep -v grep | 猫

cat returns always 0 and ignores exit code of grep

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