44

如何减少以下 bash 脚本?

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

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

我的程序应该:

  • 阅读recess.txt
  • 退出 1(或非零),如果它包含“状态:”的行不是“完美”
  • 如果不存在这样的行,则退出 0(即所有“STATUS:”行都是“Perfect”)

答案奖授予最紧凑的剧本。谢谢!

示例文件

此文件的程序应具有退出状态 0

FILE: styles.css 
STATUS: Perfect!

FILE: contour-styles.css
STATUS: Perfect!

此文件的程序应具有退出状态 1(或非零):

FILE: styles.css 
STATUS: Perfect!

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

Id's should not be styled
       1. #asdf
4

11 回答 11

54

只需否定返回值。

! grep -P "STATUS: (?!Perfect)" recess.txt
于 2014-02-14T20:08:37.130 回答
17

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

我最终使用了一个受Henri Schomäcker 答案启发的版本,但明显简化了:

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

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

  • 如果 grep 返回 0(找到匹配项),test 0 -eq 1将返回 1。
  • 如果 grep 返回 1(未找到匹配项),test 1 -eq 1将返回 0。
  • 如果 grep 返回 2(错误),test 2 -eq 1将返回 1。

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

于 2015-05-28T00:27:02.190 回答
10

要使其与set -e在子外壳中使用(and一起使用)

$ 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
$ 
于 2015-07-21T21:26:46.737 回答
9

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

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

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

我用它来快速检查 js 文件的语法:

find src/js/ -name \*js -exec node \{\} \; 2>&1 | grep -B 5 SyntaxError || exit 0 && exit 1;
于 2016-02-02T23:50:37.853 回答
5

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

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

编辑:

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

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

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

awk '/^STATUS: / && ! /Perfect/{print;ec=1} END{exit ec}' recess.txt
于 2013-03-12T17:31:26.320 回答
5

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

! grep -P "STATUS: (?!Perfect)" recess.txt || false
于 2015-06-29T23:20:58.520 回答
1

使用特殊?变量

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

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

于 2013-03-12T17:12:33.357 回答
1

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
于 2015-11-12T10:02:26.167 回答
0
[ $(grep -c -P "STATUS: (?!Perfect)" recess.txt) -eq 0 ]
于 2014-07-01T16:37:52.923 回答
0

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

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

于 2014-12-04T09:20:17.423 回答
0

由于有人已经发布了 Puppet 解决方案,我不妨添加如何反转 Ansible 运行的 shell 命令:

  - name: Check logs for errors
    command: grep ERROR /var/log/cassandra/system.log
    register: log_errors
    failed_when: "log_errors.rc == 0"

即,您只是将失败条件设置为返回代码为 0。因此,如果我们在日志中找到单词 ERROR,此命令将失败

我选择了这个而不是grep -v因为它也会反转 grep 的输出,所以我们会收到log_errors.stdout_lines我们不想要的所有 DEBUG/INFO/WARN 行。

于 2020-07-23T22:06:57.213 回答