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
Prevent grep returning an error when input doesn't match
提问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 pipefail
option (set -o pipefail
), remember to apply the exception handling (||test
) to every grep
in 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]
0
means a line is selected1
means no lines were selected2
means an error occurred
0
意味着选择了一条线1
表示未选择任何行2
表示发生错误
grep
can also return other codes if it's interrupted by a signal (e.g. 130
for SIGINT).
grep
如果它被信号中断(例如130
对于 SIGINT),它也可以返回其他代码。
Since we only want to ignore exit status 1
, we use test
to suppress that specific exit status.
由于我们只想忽略退出状态1
,因此我们使用test
抑制该特定退出状态。
- If
grep
returns0
,test
is not run. - If
grep
returns1
,test
is run and returns0
. - If
grep
returns any other value,test
is run and returns1
.
- 如果
grep
返回0
,test
则不运行。 - 如果
grep
返回1
,test
则运行并返回0
。 - 如果
grep
返回任何其他值,test
则运行并返回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
在最后一种情况下,脚本将由于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 grep
a 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 -e
and set -o pipefail
:
这样,你的管道将获得短期和简单再次,不失的特点set -e
和set -o pipefail
:
ps -ef | c1grep bar | c1grep -v grep
FYI:
供参考:
- I called it
c1grep
to emphasize it's simply catching exit status1
, nothing else. - I could have called the function
grep
instead (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 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.
所以,如果你想知道如何避免grep -v grep
甚至| grep
部分ps|grep
可言,看看一些其他的答案; 但这有点题外话恕我直言。
[1] grep
manpage
[1]grep
联机帮助页
回答by glenn Hymanman
A good trick to avoid grep -v grep
is this:
避免的一个好技巧grep -v grep
是:
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.
该正则表达式仅匹配字符串“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 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:
如果您只想扔掉 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,这将很有用。
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
无法匹配任何内容,则自动返回非零存在状态,如果匹配则返回零。所以你可以简单地说这个
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 的退出代码