在Linux shell中同时过滤输出并获得退出代码

我正在Jenkins(Jenkins是一个开源的持续集成工具)中执行一个shell命令列表。 其中一个命令是运行一个Java程序,它执行一些数据validation。 如果遇到无效date,Java程序将以非零退出代码退出,这样jenkins可以发现这次构build失败。

不幸的是,Java程序打印太多的日志到标准输出和标准错误,只有less数是有用的。 由于Java程序无法修改,我决定用grep过滤输出。 所以我写了这个shell:

java -cp $CLASSPATH MetaValidatorMain | grep -v "useless keyword1"| grep -v "useless keyword2" 

但问题是,在执行shell之后,父进程(Jenkins)得到了javagrep indead的退出代码,因此Jenkins无法确定构build是否成功。

我也试过这个:

 (java -cp $CLASSPATH MetaValidatorMain || exit 1) | grep -v "useless keyword1"| grep -v "useless keyword2" 

也没有工作。

任何人都可以告诉我如何编写shell的行来筛选输出,并获得相同的正确退出代码。

谢谢

有3种方法可以做到这一点。 但是,您目前的设置应该工作。 这里的原因是,如果命令失败,grep将不匹配任何东西,所以grep将返回状态1 (除非程序总是显示文本,无论如何)。

Pipefail

第一种方法是设置pipefail选项。 这是最简单的,它基本上设置退出状态$? 到最后一个程序的退出代码退出非零(如果全部成功退出,则返回零)。

 # false | true; echo $? 0 # set -o pipefail # false | true; echo $? 1 

$ PIPESTATUS

Bash也有一个名为$PIPESTATUS的变量,它包含了最后一个命令中所有程序的退出状态。

 # true | true; echo "${PIPESTATUS[@]}" 0 0 # false | true; echo "${PIPESTATUS[@]}" 1 0 # false | true; echo "${PIPESTATUS[0]}" 1 # true | false; echo "${PIPESTATUS[@]}" 0 1 

您可以使用第三个命令示例来获取所需的管道中的特定值。

尽管这个解决方案可能不可用。 我认为$PIPESTATUS可能已经添加在一个相当新的版本的bash中,你的操作系统可能没有它。

单独执行

这是解决方案中最难处理的。 分别运行每个命令并捕获状态

 # java -cp $CLASSPATH MetaValidatorMain > /tmp/outfile.txt 2>&1 # RETURN_CODE=$? # grep -v "useless keyword1" /tmp/outfile | grep -v "useless keyword2" # exit RETURN_CODE 

很长一段时间,但是你可以将程序输出重定向到一个文件,捕获返回,然后grep你想要的内容的输出文件:

 java -cp $CLASSPATH MetaValidatorMain > /tmp/outfile.txt 2>&1 RETURN_CODE=$? grep -v "useless keyword1" /tmp/outfile | grep -v "useless keyword2" exit RETURN_CODE