Linux:运行多个命令而不会丢失单个返回码?

时间:2017-01-04 12:30:10

标签: java linux bash command-line

我读过this question,但我的问题是我有“大量”命令可以运行;我需要一个适用于系统调用的解决方案。

我们有一个退出任务,它基本上会在我们的JVM中触发很多“清理”活动。我正在处理的部分必须调用某个脚本,而不是一次,但 n 次!

Java端的当前实现创建 n ProcessBuilder个对象;并且每个运行一个简单的bash script.sh parm ...其中parm在每次运行时都不同。

现在我想将Java端更改为仅使用ProcessBuilder进行一次系统调用(而不是 n )。

我可以使用以下命令:

bash script.sh parm1 ; bash script.sh parm2 ; ... ; bash script.sh parmN

现在问题是:如果其中一次运行失败......我希望所有其他运行仍然发生;但我想最终得到一个“坏”的返回码。

是否有一种简单,优雅的方法来实现这一点,一种使用来自系统调用的命令字符串?

4 个答案:

答案 0 :(得分:1)

您可以随时在子shell中构建返回码,然后使用算术评估在最后检查它们。例如,在我的测试系统(cygwin)上,在bash提示下:

$  ( 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

                                        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.

所以,在你的情况下,

(r=; bash script.sh parm1 ; r=$r$?; bash script.sh parm2 ; r=$r$?; ... ; bash script.sh parmN r=$r$?; (($r==0)) )

使用保存返回码的函数s,您也可以稍微缩短一下:

$ (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$?;}定义了一个更新s的函数r。然后可以在每个命令之后运行ss定义中的空格和分号是必需的。

发生了什么?

  • r=r初始化为空字符串。这将保留我们的返回值。
  • 在每个命令之后,r=$r$?将该命令的退出状态添加到rr中没有空格,通过构造,所以我为了简洁而省略了引号。请参阅下文,了解有关负回报值的说明。
  • 如果(($r==0))评估为r,则最后0成功。因此,如果所有命令都成功,r将为000 ... 0,等于0
  • 子shell的退出状态是其最后一个命令的退出状态,此处为(($r==0))测试。因此,如果r全部为零,则子shell将报告成功。如果没有,子shell将报告失败($?==1)。

负退出值

如果子shell中的某些程序可能具有负退出值,则这可能仍然有效。例如,0-255100255是一个不等于零的有效表达式。但是,如果您有两个命令,第一个退出127,第二个退出-127r将为127-127,为零。

要避免此问题,请将每个r=$r$?替换为r=$r$((! ! $?))。双重逻辑否定$((! ! $?))0转换为0,将任何其他值(正面或负面)转换为1。然后r将只包含01值,因此(($r==0))测试将是正确的。 (每次!之后你确实需要空格,所以bash并不认为你是在试图引用你的命令历史。)

答案 1 :(得分:0)

所有退出代码的二进制OR-ing将为零(0)&#34;如果&#34;和&#34;只有&#34;所有退出代码均为零(0)。

您可以使用这个简单的算术表达式获得正在运行的退出代码:

excode=((excode | $?))

要运行所有参数,您可以使用脚本(&#34; callcmd&#34;),如:

#!/bin/bash
excode=0
for    i
do     cmd "$i"
       excode=((excode | $?))
done
echo "The final exit code is $excode"
# if [[ $excode -ne 0 ]]; exit 1; fi     # An alternative exit solution.

从java调用此脚本(&#34; callcmd&#34;):

callcmd parm1 parm2 parm3 … parmi … parmN

每个命令的输出在通常的标准输出中可用,并且错误字符串(如果有的话)也可以在stderr中使用(但是所有命令都将被连接,因此命令&#34; cmd&#34;应该识别parm正在发出错误。)

答案 2 :(得分:0)

r=0; for parm in parm1 parm2 ... parmN; do
    bash script.sh "$parm" || r=1
done
exit "$r" 

答案 3 :(得分:-1)

你可以这样做

bash script.sh parm1 || echo "FAILED" > some.log ; bash script.sh parm2 || echo "FAILED" > some.log; ... ; bash script.sh parmN|| echo "FAILED" > some.log 然后检查是否有some.log文件。

|| - 它是简单的bash逻辑或(如果前一个的退出状态为非零则执行)