此问题非常奇怪,我无法在线找到有关此文档的任何文档。在下面的代码片段中,我仅尝试并行运行一堆子流程,在它们退出时打印一些内容,最后收集/打印其退出代码。我发现,如果不捕获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时继续等待,我实际上会得到预期的结果)
答案 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,然后立即执行陷阱。“
因此,您已经掌握了上面的脚本中的内容:
sleep 6
从后台开始sleep 3
从后台开始wait
开始等待sleep 6
sleep 3
终止,并在触发中断等待时触发SIGCHLD陷阱,返回128 + SIGCHLD = 145 sleep 6
终止,因此在脚本退出后,“立即返回'sleep 6”