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

发布于 2024-11-18 02:46:10 字数 413 浏览 1 评论 0原文

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

 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 但无济于事。

有什么解决办法吗?谢谢

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

 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

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

 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.

Is there any solution to that? Thx

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

烟沫凡尘 2024-11-25 02:46:11

当然:

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

或者甚至:

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

Sure:

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

Or even:

ps -ef | grep bar | grep -v grep | cat
各自安好 2024-11-25 02:46:11

简短回答

请写下

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

如果您使用set -e

。如果您使用 bash 的 pipefail 选项 (set -o pipelinefail),请记住应用异常处理 (||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 表示没有选择任何行
  • < code>2 表示发生错误

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

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

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

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

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

按照 肖恩


[附加] 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

[附加] ps + grep

因此,如果您想知道如何避免 grep -v grep 甚至 | grepps|grep 的一部分,看看其他一些答案;但这有点题外话。


[1] grep 文档(POSIX 规范, GNU grep 文档FreeBSD 联机帮助页)

Short answer

Write

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

if you are using set -e.

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

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

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

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

Explained

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

  • 0 means a line is selected
  • 1 means no lines were selected
  • 2 means an error occurred

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

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

  • If grep returns 0, test is not run.
  • If grep returns 1, test is run and returns 0.
  • If grep returns any other value, test is run and returns 1.

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

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

as suggested by Sean.


[additional] usage in shell scripts

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

# "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 -e and set -o pipefail:

ps -ef | c1grep bar | c1grep -v grep

FYI:

  • I called it c1grep to emphasize it's simply catching exit status 1, nothing else.
  • I could have called the function grep instead (grep() { env grep "$@" ...; }), but I prefer a less confusing and more explicit name, c1grep.

[additional] ps + grep

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


[1] grep documentation (POSIX spec, GNU grep docs, FreeBSD manpage)

老子叫无熙 2024-11-25 02:46:11

避免 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'

A good trick to avoid grep -v grep is this:

ps -ef | grep '[b]ar'

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


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

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'
魔法唧唧 2024-11-25 02:46:11

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

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

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

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

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,不需要两次甚至一次。

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

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.

ps automatically will return with a non-zero exist status if -C fails to match anything and with zero if it matches. So you could simply say this

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.

兲鉂ぱ嘚淚 2024-11-25 02:46:11

尝试这样做:

ps auxw | grep -v grep | grep -v猫

cat 始终返回 0 并忽略 grep 的退出代码

Try to make so:

ps auxw | grep -v grep | cat

cat returns always 0 and ignores exit code of grep

七七 2024-11-25 02:46:11
foo=`ps -ef | grep bar | grep -v grep` || true
foo=`ps -ef | grep bar | grep -v grep` || true
梦断已成空 2024-11-25 02:46:11

如果您使用 grep,所有这些都非常混乱,有时它找不到任何匹配项,而您只想继续。如果您安装了 ruby​​,则可以执行 ruby​​ -ne 'print if /bar/',如果没有匹配项,它将没有输出。

All of it's pretty messy if you are using grep and it sometimes does not find any matches and you want to just continue. If you have ruby installed, you can do ruby -ne 'print if /bar/', and it will just have no output if there are no matches.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文