Bash:为什么过早等待 returns 代码 145

Bash: why wait returns prematurely with code 145

这个问题很奇怪,我在网上找不到任何关于这个的文档。在下面的代码片段中,我只是试图 运行 一堆并行的子进程,在它们退出时打印一些东西,并在最后 collect/print 它们的退出代码。我发现,如果没有捕捉到 SIGCHLD,事情就会像我预期的那样工作,但是,当我捕捉到信号时,事情就会中断。这是代码:

#!/bin/bash

#enabling job control
set -m

cmd_array=( "$@" )         #array of commands to run in parallel
cmd_count=$#               #number of commands to run
cmd_idx=0;                 #current index of command
cmd_pids=()                #array of child proc pids
trap 'echo "Child job existed"' SIGCHLD #setting up signal handler on SIGCHLD

#running jobs in parallel
while [ $cmd_idx -lt $cmd_count ]; do
  cmd=${cmd_array[$cmd_idx]} #retreiving the job command as a string
  eval "$cmd" &
  cmd_pids[$cmd_idx]=$!            #keeping track of the job pid
  echo "Job #$cmd_idx launched '$cmd']"
  (( cmd_idx++ ))
done

#all jobs have been launched, collecting exit codes
idx=0
for pid in "${cmd_pids[@]}"; do
  wait $pid
  child_exit_code=$?
  if [ $child_exit_code -ne 0 ]; then
    echo "ERROR: Job #$idx failed with return code $child_exit_code. [job_command: '${cmd_array[$idx]}']"
  fi
  (( idx++ ))
done

当您尝试 运行 以下命令时,您会发现有问题:

./parallel_script.sh "sleep 20; echo done_20" "sleep 3; echo done_3"

这里有趣的是,一旦信号处理程序被调用(当睡眠 3 完成时),等待(正在等待睡眠 20)立即被 return 代码 145。即使在脚本完成后,我也可以看出 sleep 20 仍然是 运行ning。 我无法从 wait 中找到有关此类 return 代码的任何文档。任何人都可以阐明这里发生了什么吗?

(顺便说一句,如果我在等待时添加一个while循环并在return代码为145时继续等待,我实际上得到了我期望的结果)

感谢@muru,我能够使用更少的代码重现 "problem",如下所示:

#!/bin/bash

set -m
trap "echo child_exit" SIGCHLD

function test() {
 sleep 
 echo "'sleep ' just returned now"
}

echo sleeping for 6 seconds in the background
test 6 &
pid=$!
echo sleeping for 2 second in the background
test 2 &
echo waiting on the 6 second sleep
wait $pid
echo "wait return code: $?"

如果你运行这个你会得到以下输出:

linux:~$ sh test2.sh
sleeping for 6 seconds in the background
sleeping for 2 second in the background
waiting on the 6 second sleep
'sleep 2' just returned now
child_exit
wait return code: 145
lunux:~$ 'sleep 6' just returned now

解释:

正如@muru 指出的那样“当命令终止于编号为 N 的致命信号时,Bash 使用值 128+N 作为退出状态。 “(c.f。Bash manual on Exit Status)。 现在误导我的是 "fatal" 信号。我一直在寻找一个在某处失败的命令,但什么也没做。

Bash manual on Signals 中更深入地挖掘:“当 Bash 通过 wait 内置函数等待异步命令时,接收到一个陷阱的信号set 将导致等待内置函数立即 return,退出状态大于 128,之后立即执行陷阱。"

好了,上面的脚本中发生的事情如下:

  1. sleep 6 在后台启动
  2. sleep 3 在后台启动
  3. wait 开始等待 sleep 6
  4. sleep 3 终止并且 SIGCHLD 陷阱如果触发中断等待,returns 128 + SIGCHLD = 145
  5. 我的脚本退出,因为它不再等待
  6. 后台 sleep 6 终止,因此在脚本已经退出
  7. 之后“'sleep 6' 刚刚 returned”