Bash:为什么等待早于代码145返回

时间:2018-11-20 23:36:19

标签: bash shell subprocess signals wait

此问题非常奇怪,我无法在线找到有关此文档的任何文档。在下面的代码片段中,我仅尝试并行运行一堆子流程,在它们退出时打印一些内容,最后收集/打印其退出代码。我发现,如果不捕获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中等待)立即被返回代码145中断。告诉即使脚本完成后睡眠20仍在运行。 我从等待中找不到任何有关此类返回码的文档。任何人都可以对这里发生的事情有所了解吗?

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

1 个答案:

答案 0 :(得分:1)

由于@muru,我能够使用更少的代码来重现“问题”,您可以在下面看到它:

#!/bin/bash

set -m
trap "echo child_exit" SIGCHLD

function test() {
 sleep $1
 echo "'sleep $1' 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作为退出状态。”(参见{Bash manual on Exit Status) 。 现在,在这里误导我的是“致命”信号。我一直在寻找一个命令,该命令会在某处什么都没做的情况下失败。

Bash manual on Signals中进行更深的挖掘:“ 当Bash通过wait内置等待异步命令时,接收到已设置陷阱的信号将导致wait内置返回立即退出状态大于128,然后立即执行陷阱。

因此,您已经掌握了上面的脚本中的内容:

  1. sleep 6从后台开始
  2. sleep 3从后台开始
  3. wait开始等待sleep 6
  4. sleep 3终止,并在触发中断等待时触发SIGCHLD陷阱,返回128 + SIGCHLD = 145
  5. 我的脚本退出了,因为它不再等待了
  6. 背景sleep 6终止,因此在脚本退出后,“立即返回'sleep 6”