为什么bash eval在后台命令失败时返回零?

Cha*_*der 2 bash eval

编辑这篇文章,原文位于"谢谢!"的底部.

command='a.out arg1 arg2 &'
eval ${command}
if [ $? -ne 0 ]; then
   printf "Command \'${command}\' failed\n"
   exit 1
fi
wait
Run Code Online (Sandbox Code Playgroud)

这是一个演示问题的测试脚本,我在原帖中过于简化了.注意第2行中的&符号和wait命令.这些更忠实地代表了我的剧本.在重要的情况下,&符有时在那里,有时不在,它的存在是由用户指定的标志确定的,该标志指示是否进行长算术计算.并且,如果它很重要,我实际上是在背景许多(十二个)过程,即${command[0..11]}.如果有任何失败,我希望脚本死掉.我使用'wait'来同步所有进程的成功返回.快乐(有点)使用另一种方法,但这几乎可行.

&符号(用于背景)似乎导致了问题.当${command}省略符号,脚本运行预期:可执行的a.out是找不到的,投诉到该效果被发出,并且$?非零,因此主机脚本退出.如果${command}包含&符号,则会发出相同的投诉,但是$?为零,因此脚本继续执行.我希望脚本在a.out失败时立即死亡但是如何从后台进程获得非零返回值?

谢谢!

(原帖):

我有一个使用表单命令的bash脚本

eval ${command}
if [ $? -ne 0 ]; then
   printf "Command ${command} failed"
   exit 1
fi
Run Code Online (Sandbox Code Playgroud)

其中$ {command}是一串单词,例如"a.out arg1 ... argn".问题是$?即使${command}失败,来自eval(即)的返回码始终为零.从上面的代码段中删除"eval"允许返回正确的返回代码($?),从而停止脚本.我需要将我的命令字符串保存在变量(${command})中以便在其他地方操作它,并且只是在${command}没有eval的情况下运行 不能很好地用于其他原因.使用eval时如何捕获正确的返回码?

谢谢!查理

Joh*_*024 5

&符号(用于背景)似乎导致了问题.

那是正确的.

在命令完成之前,shell无法知道命令的退出代码.当您在后台放置命令时,shell 不会等待完成.因此,它无法知道后台命令的(未来)返回状态.

这记录在man bash:

如果命令由控制操作符&终止,则shell在子shell中在后台执行命令.shell不等待命令完成,返回状态为0.

换句话说,在后台放置命令后的返回码始终为0,因为shell无法预测尚未完成的命令的未来返回码.

如果要在后台查找命令的返回状态,则需要使用该wait命令.

例子

该命令false始终将返回状态设置为1:

$ false ; echo status=$?
status=1
Run Code Online (Sandbox Code Playgroud)

但是,请注意,如果我们背景会发生什么:

$ false & echo status=$?
[1] 4051
status=0
Run Code Online (Sandbox Code Playgroud)

状态为0,因为该命令是在后台放置的,而shell无法预测其未来的退出代码.如果我们等一会儿,我们会看到:

$ 
[1]+  Exit 1                  false
Run Code Online (Sandbox Code Playgroud)

在这里,shell正在通知我们完成了背景任务并且它的返回状态正如它应该的那样:1.

在上面,我们没有使用eval.如果我们这样做,没有变化:

$ eval 'false &' ; echo status=$?
[1] 4094
status=0
$ 
[1]+  Exit 1                  false
Run Code Online (Sandbox Code Playgroud)

如果您确实需要后台命令的返回状态,请使用wait.例如,这显示了如何捕获返回状态false:

$ false & wait $!; echo status=$?
[1] 4613
[1]+  Exit 1                  false
status=1
Run Code Online (Sandbox Code Playgroud)