我读了这个问题,但我的问题是我有"很多"命令要运行;我需要一个适用于系统调用的解决方案。
我们有一个退出任务,它基本上在我们的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
现在的问题是:如果其中一个运行失败......我希望所有其他跑步仍然进行;但我想最终得到一个"错误"的返回代码。
有没有一种简单、优雅的方法来实现这一点,一种适用于来自系统调用的命令字符串的方法?
您可以随时在子外壳中构建返回代码,然后在最后使用算术计算检查它们。 例如,在我的测试系统(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$?;}
定义了一个将更新r
的函数s
。 然后,可以在每个命令之后运行s
。s
定义中的空格和分号是必需的。
发生了什么事情?
r=
r
初始化为空字符串。 这将在我们前进的过程中保持我们的返回值。- 在每个命令之后,
r=$r$?
将该命令的退出状态附加到r
上。r
中没有空格,通过构造,所以我省略了引号以简洁。 有关负返回值的说明,请参阅下文。 - 最后,如果
r
计算结果为0
,则(($r==0))
成功。 因此,如果所有命令都成功,r
将被000
...0
,等于0
。
子外壳的退出状态 - 是其最后一个命令的退出状态,此处为
(($r==0))
测试。 因此,如果r
全为零,则子外壳将报告成功。 否则,子外壳将报告失败($?==1
)。
负退出值
如果子外壳中的某些程序可能具有负退出值,这可能仍然有效。 例如,0-255100255
是不等于零的有效表达式。 但是,如果你有两个命令,第一个以127
退出,第二个以-127
退出,r
将是127-127
,即零。
若要避免此问题,请将每个r=$r$?
替换为r=$r$((! ! $?))
。 双重逻辑否定$((! ! $?))
将0
转换为0
,将任何其他值(正值或负值)转换为1
。 然后r
将只包含0
和1
值,因此(($r==0))
测试是正确的。 (每个!
后都需要空格,因此 bash 不会认为您正在尝试引用您的命令历史记录。
所有退出代码的二进制 OR-ing 将为零 (0) "if"和"仅当"所有退出代码为零 (0)。
您可以使用以下简单的算术表达式获取正在运行的退出代码:
excode=((excode | $?))
要运行所有参数,您可以使用脚本("callcmd"),如下所示:
#!/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.
其中,这个脚本("callcmd")从java调用为:
callcmd parm1 parm2 parm3 … parmi … parmN
每个命令的输出在通常的标准输出中可用,错误字符串(如果有的话)也将在 stderr 中可用(但所有字符串都将连接起来,因此命令"cmd"应识别哪个参数发出错误)。
r=0; for parm in parm1 parm2 ... parmN; do
bash script.sh "$parm" || r=1
done
exit "$r"
你可以这样做
bash script.sh parm1 || echo "FAILED" > some.log ; bash script.sh parm2 || echo "FAILED" > some.log; ... ; bash script.sh parmN|| echo "FAILED" > some.log
然后检查是否有一些.log文件。
|| - 这是简单的 bash 逻辑或(如果前一个的退出状态不为零,则执行)