I am running a job in Jenkins(Jenkins is an open source continuous integration tool) by executing a list of shell commands. One of the command is to run a Java program which does some data validation. If meets with invalid date, the Java program will exit with a none-zero exit code so that Jenkins can discover that this time the build fails.
Unfortunately the Java program prints too much log to stdout and stderr, only a few of them are useful. Since the Java program can not be modified, I decide to filter the output with grep. So I wrote the shell as:
java -cp $CLASSPATH MetaValidatorMain | grep -v "useless keyword1"| grep -v "useless keyword2"
But the problem is that, after the execution of the line of shell, the parent process(Jenkins) got exit code of grep indead of java, so that Jenkins could not determine whether the build was success.
I also tried this:
(java -cp $CLASSPATH MetaValidatorMain || exit 1) | grep -v "useless keyword1"| grep -v "useless keyword2"
also did not work.
Could anyone tell me how could I write the line of shell to filter output and obtain the right exit code at the same.
thx
Bit of a long way round, but you could redirect the program output to a file, capture the return and then grep the output file for the content you want:
java -cp $CLASSPATH MetaValidatorMain > /tmp/outfile.txt 2>&1
RETURN_CODE=$?
grep -v "useless keyword1" /tmp/outfile | grep -v "useless keyword2"
exit RETURN_CODE
There are 3 ways of doing this. However your current setup should work. The reason here being that the grep won't match anything if the command fails, so grep will return with status 1 (unless the program always shows that text no matter what).
The first way is to set the pipefail option. This is the simplest and what it does is basically set the exit status $? to the exit code of the last program to exit non-zero (or zero if all exited successfully).
# false | true; echo $?
0
# set -o pipefail
# false | true; echo $?
1
Bash also has a variable called $PIPESTATUS which contains the exit status of all the programs in the last command.
# true | true; echo "${PIPESTATUS[@]}"
0 0
# false | true; echo "${PIPESTATUS[@]}"
1 0
# false | true; echo "${PIPESTATUS[0]}"
1
# true | false; echo "${PIPESTATUS[@]}"
0 1
You can use the 3rd command example to get the specific value in the pipeline that you need.
This solution might not be available though. I think $PIPESTATUS might have been added in a fairly recent version of bash, and your OS may not have it.
This is the most unwieldy of the solutions. Run each command separately and capture the status
# java -cp $CLASSPATH MetaValidatorMain > /tmp/outfile.txt 2>&1
# RETURN_CODE=$?
# grep -v "useless keyword1" /tmp/outfile | grep -v "useless keyword2"
# exit RETURN_CODE