I read this question, but my problem is that I have "plenty" of commands to run; and I need a solution that works for a systems calls.
We have an exit task that basically triggers a lot of "cleanup" activity within our JVM. The part I am working on has to call a certain script, not once, but n times!
The current implementation on the Java side creates n ProcessBuilder objects; and each one runs a simple bash script.sh parm ... where parm is different on each run.
Now I want to change the Java side to only make one system call (instead of n) using ProcessBuilder.
I could just use the following command:
bash script.sh parm1 ; bash script.sh parm2 ; ... ; bash script.sh parmN
Now the thing is: if one of the runs fails ... I want all other runs to still take place; but I would like to get a "bad" return code in the end.
Is there a simple, elegant way to achieve that, one that works with command strings coming from system calls?
You can build up the return codes in a subshell as you go, then check them at the end using arithmetic evaluation. E.g., on my test system (cygwin), at a bash prompt:
$ ( r=; echo "foo" ; r=$r$?; echo "bar" ; r=$r$? ; echo "baz" ; r=$r$? ; (($r==0)) )
foo
bar
baz
$ echo $?
0 <--- all the commands in the subshell worked OK, so the status is OK
and
VVVV make this echo fail
$ ( r=; echo "foo" ; r=$r$?; echo "bar" 1>&- ; r=$r$? ; echo "baz" ; r=$r$? ; (($r==0)) )
foo
-bash: echo: write error: Bad file descriptor
baz
$ echo $?
1 <--- failure code, but all the commands in the subshell still ran.
So, in your case,
(r=; bash script.sh parm1 ; r=$r$?; bash script.sh parm2 ; r=$r$?; ... ; bash script.sh parmN r=$r$?; (($r==0)) )
You can also make that slightly shorter with a function s that stashes the return code:
$ (r=;s(){ r=$r$?;}; echo "foo" ; s; echo "bar" 1>&-; s; echo "baz" ; s; (($r==0)) )
foo
-bash: echo: write error: Bad file descriptor
baz
$ echo $?
1
s(){ r=$r$?;} defines a function s that will update r. Then s can be run after each command. The space and semicolon in the definition of s are required.
r= initializes r to an empty string. That will hold our return values as we go.r=$r$? tacks that command's exit status onto r. There are no spaces in r, by construction, so I left off the quotes for brevity. See below for a note about negative return values.(($r==0)) succeeds if r evaluates to 0. So, if all commands succeeded, r will be 000...0, which equals 0.(($r==0)) test. So if r is all zeros, the subshell will report success. If not, the subshell will report failure ($?==1).If some of the programs in the subshell may have negative exit values, this will probably still work. For example, 0-255100255 is a valid expression that is not equal to zero. However, if you had two commands, the first exited with 127, and the second exited with -127, r would be 127-127, which is zero.
To avoid this problem, replace each r=$r$? with r=$r$((! ! $?)). The double logical negation $((! ! $?)) converts 0 to 0 and any other value, positive or negative, to 1. Then r will only contain 0 and 1 values, so the (($r==0)) test will be correct. (You do need spaces after each ! so bash doesn't think you're trying to refer to your command history.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With