Bash:以与 grep 命令相反的状态退出的单行程序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15367674/
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-18 04:49:45  来源:igfitidea点击:

Bash: One-liner to exit with the opposite status of a grep command?

regexbashgrepexitexit-code

提问by Sean Adkinson

How can I reduce the following bash script?

如何减少以下 bash 脚本?

grep -P "STATUS: (?!Perfect)" recess.txt && exit 1
exit 0

It seems like I should be able to do it with a single command, but I have a total of 3 here.

看起来我应该可以用一个命令来完成,但我这里总共有 3 个。

My program should:

我的程序应该:

  • Read recess.txt
  • Exit 1 (or non-zero) if it contains a line with "STATUS: " of NOT "Perfect"
  • Exit 0 if no such line exists (i.e. all "STATUS: " lines are "Perfect")
  • 阅读休会.txt
  • 退出 1(或非零)如果它包含带有“STATUS:”或“非完美”的行
  • 如果不存在这样的行,则退出 0(即所有“STATUS:”行都是“Perfect”)

The answer award goes to the tightest script. Thanks!

答案奖授予最严格的剧本。谢谢!

Example files

示例文件

Program should have exit status 0for this file:

对于此文件,程序应该具有退出状态 0

FILE: styles.css 
STATUS: Perfect!

FILE: contour-styles.css
STATUS: Perfect!

Program should have exit status 1(or non-zero) for this file:

对于此文件,程序应该具有退出状态 1(或非零):

FILE: styles.css 
STATUS: Perfect!

FILE: contour-styles.css
STATUS: Busted 
FAILURES: 1 failure

Id's should not be styled
       1. #asdf

回答by Tgr

Just negatethe return value.

只需否定返回值。

! grep -P "STATUS: (?!Perfect)" recess.txt

回答by cincodenada

I came across this, needing an onlyifstatement for Puppet. As such, Tgr's bash solutionwouldn't work, and I didn't want to expand the complexity as in Christopher Neylan's answer.

我遇到了这个,需要onlyifPuppet的声明。因此,Tgr 的 bash 解决方案不起作用,而且我不想像Christopher Neylan 的回答那样扩展复杂性。

I ended up using a version inspired by Henri Schom?cker's answer, but notably simplified:

我最终使用了一个受Henri Schom?cker's answer启发的版本,但明显简化了:

grep -P "STATUS: (?!Perfect)" recess.txt; test $? -eq 1

Which very simply inverts the exit code, returning success only if the text is not found:

这非常简单地反转退出代码,只有在找不到文本时才返回成功:

  • If grep returns 0 (match found), test 0 -eq 1will return 1.
  • If grep returns 1 (no match found), test 1 -eq 1will return 0.
  • If grep returns 2 (error), test 2 -eq 1will return 1.
  • 如果 grep 返回 0(找到匹配),test 0 -eq 1则返回 1。
  • 如果 grep 返回 1(未找到匹配项),test 1 -eq 1则返回 0。
  • 如果 grep 返回 2(错误),test 2 -eq 1将返回 1。

Which is exactly what I wanted: return 0 if no match is found, and 1 otherwise.

这正是我想要的:如果找不到匹配项,则返回 0,否则返回 1。

回答by Robpol86

To make it work with set -esurround it in a sub-shell with (and ):

要使其set -e在子外壳中使用(和包围它,请执行以下操作)

$ cat test.sh 
#!/bin/bash

set -ex
(! ls /tmp/dne)
echo Success
$ ./test.sh 
+ ls /tmp/dne
ls: cannot access /tmp/dne: No such file or directory
+ echo Success
Success
$ mkdir /tmp/dne
$ ./test.sh 
+ ls /tmp/dne
$ 

回答by gcb

if anyone gets here looking for a bash return code manipulation:

如果有人来这里寻找 bash 返回码操作:

(grep <search> <files> || exit 0 && exit 123;)

this will return 0(success) when grep finds nothing, and return 123(failure) when it does. The parenthesis are in case anyone test it as is on the shell prompt. with parenthesis it will not logout on the exit, but just exit the subshell with the same error code.

0当 grep 什么也没找到时,这将返回(成功),并123在它找到时返回(失败)。括号是以防有人在 shell 提示符下测试它。带括号它不会在退出时注销,而只是退出具有相同错误代码的子shell。

i use it for a quick syntax check on js files:

我使用它对 js 文件进行快速语法检查:

find src/js/ -name \*js -exec node \{\} \; 2>&1 | grep -B 5 SyntaxError || exit 0 && exit 1;

回答by Christopher Neylan

You actually don't need to use exitat all. Logically, no matter what the result of grep, your script is going to exit anyway. Since the exit value of a shell script is the exit code of the last command that was run, just have greprun as the last command, using the -voption to invert the match to correct the exit value. Thus, your script can reduce to just:

你实际上根本不需要使用exit。从逻辑上讲,无论 grep 的结果如何,您的脚本都将退出。由于 shell 脚本的退出值是运行的最后一个命令的退出代码,只需grep作为最后一个命令运行,使用-v选项反转匹配以更正退出值。因此,您的脚本可以简化为:

grep -vqP "STATUS: (?!Perfect)" recess.txt

EDIT:

编辑:

Sorry, the above does not work when there are other types of lines in the file. In the interest of avoiding running multiple commands though, awkcan accomplish the entire shebang with something like:

抱歉,当文件中有其他类型的行时,上述方法不起作用。为了避免运行多个命令,awk可以使用以下内容完成整个shebang:

awk '/STATUS: / && ! /Perfect/{exit 1}' recess.txt

If you decide you want the output that grep would have provided, you can do:

如果您决定需要 grep 提供的输出,您可以执行以下操作:

awk '/^STATUS: / && ! /Perfect/{print;ec=1} END{exit ec}' recess.txt

回答by Eric Woodruff

Just negating the return value doesn't work in a set -e context. But you can do:

仅否定返回值在 set -e 上下文中不起作用。但你可以这样做:

! grep -P "STATUS: (?!Perfect)" recess.txt || false

回答by M Hutson

The problem with the grep answers is that if the file is empty you also get a clean response, as if the file had a perfect. So personally I gave up on grep for this and used awk.

grep 答案的问题在于,如果文件为空,您也会得到一个干净的响应,就好像该文件有一个完美的。所以我个人为此放弃了grep并使用了awk。

awk 'BEGIN{ef=2}; /STATUS: Perfect/{ ef=0;}; /STATUS: Busted/{ print;eff=3;}; END{exit (ef+eff)}' a.txt ; echo $?

This has exit status:
 0 :  Perfect and !Busted
 2 : !Perfect and  Busted
 3 :  Perfect and  Busted
 5 : !Perfect and !Busted

回答by Oliver Charlesworth

Use the special ?variable:

使用特殊?变量

grep -P "STATUS: (?!Perfect)" recess.txt
exit $((1-$?))

(But note that grepmay also return 2, so it's not clear what you'd want to occur in such cases.)

(但请注意,它grep也可能返回 2,因此不清楚在这种情况下您希望发生什么。)

回答by Chris

[ $(grep -c -P "STATUS: (?!Perfect)" recess.txt) -eq 0 ]

回答by Henri Schom?cker

I also needed such a solution for writing puppet only if statements and came up with the following command:

我还需要这样一个解决方案来编写 puppet only if 语句并想出了以下命令:

/bin/grep --quiet 'root: [email protected]' /etc/aliases; if [ $? -eq 0 ]; then test 1 -eq 2; else test 1 -eq 1; fi;

/bin/grep --quiet 'root: [email protected]' /etc/aliases; if [ $? -eq 0 ]; then test 1 -eq 2; else test 1 -eq 1; fi;