Answers:
有了bash
,你将有保证,除非你已经开始另一个后台作业(和提防后台作业可以开始&
,但也与coproc
对之间,并与进程替换)foo &
和wait
。
POSIX要求Shell至少要bash
记住25个作业离开后的退出状态,但要记住的更多。
现在,如果您这样做:
foo & pid=$!
...
bar &
wait "$pid"
您无法保证bar
不会获得与pid相同的pid foo
(如果foo
已在bar
开始时间之前终止),因此即使不太可能,wait "$pid"
也可能会为您提供退出状态bar
。
您可以使用以下方法重现它:
bash -c '(exit 12; foo) & pid=$!
while : bar & [ "$pid" != "$!" ]; do :;done
wait "$pid"; echo "$?"'
最终会给您0
而不是12
。
为避免此问题,一种方法是将其编写为:
{
foo_pid=$!
while ps -p "$foo_pid"
do
ping -c 1 localhost
done
bar &
...
read <&3 ret
if [ "$ret" = 0 ]; then
echo foo was sucessful.
fi
} 3< <(foo > logfile 2>&1; echo "$?")
是的,您可以依靠wait "$!"
获取后台作业的状态。作为脚本运行时,bash不会自动收集完成的后台作业。因此,如果运行wait
,它将在wait
调用时收集作业。
您可以使用简单的脚本对此进行测试:
#!/bin/bash
sh -c 'sleep 1; exit 22' &
sleep 5
echo "FG: $?"
wait %1
echo "BG: $?"
将输出:
FG: 0
BG: 22
wait %1
“睡眠5”完成后立即收集后台进程,因此出现“无此类作业” 的失败。
%1
代替了你$!
。
bash -c '(sleep 1;exit 5) & sleep 2; wait %1; echo $?'
(也是如此非交互的)无法获取该死任务的退出状态。听起来像个虫子。
set +e
。似乎bash的set -e
函数会在引发错误的退出代码后立即杀死该脚本,方法是wait
我相信您的假设是正确的。这是man bash
有关等待后台进程的摘录。
如果n指定不存在的进程或作业,则返回状态为127。否则,返回状态为等待的最后一个进程或作业的退出状态。
所以也许你应该检查127
有一个类似的问题,答案可能完全不同。
编辑1
受@Stephane的评论和答案的启发,我扩展了他的脚本。在开始松动之前,我可以启动约34个后台进程。
后退
$ cat tback
plist=()
elist=()
slist=([1]=12 [2]=15 [3]=17 [4]=19 [5]=21 [6]=23)
count=30
#start background tasksto monitor
for i in 1 2 3 4
do
#echo pid $i ${plist[$i]} ${slist[$i]}
(echo $BASHPID-${slist[$i]} running; exit ${slist[$i]}) &
plist[$i]=$!
done
echo starting $count background echos to test history
for i in `eval echo {1..$count}`
do
echo -n "." &
elist[$i]=$!
done
# wait for each background echo to complete
for i in `eval echo {1..$count}`
do
wait ${elist[$i]}
echo -n $?
done
echo ""
# Now wait for each monitored process and check return status with expected
failed=0
for i in 1 2 3 4
do
wait ${plist[$i]}
rv=$?
echo " pid ${plist[$i]} returns $rv should be ${slist[$i]}"
if [[ $rv != ${slist[$i]} ]]
then
failed=1
fi
done
wait
echo "Complete $failed"
if [[ $failed = "1" ]]
then
echo Failed
else
echo Success
fi
exit $failed
$
在我的系统上产生
$ bash tback
14553-12 running
14554-15 running
14555-17 running
starting 30 background echos to test history
14556-19 running
..............................000000000000000000000000000000
pid 14553 returns 12 should be 12
pid 14554 returns 15 should be 15
pid 14555 returns 17 should be 17
pid 14556 returns 19 should be 19
Complete 0
Success
bash -c '(exit 12) & sleep 1; wait "$!"; echo "$?"'
bash
松散的路线(即使在开始了成千上万的工作之后),我的示例演示了pid被重用,这也可能是您在案例中观察到的。
wait
不起作用。在提示出现之前(默认情况下),将收集过程并丢弃退出状态。