Bash脚本在Ctrl + C上杀死背景(大)孩子

时间:2012-07-27 22:58:04

标签: bash shell process wait kill

我有一个Bash脚本(Bash 3.2,Mac OS X 10.8),它可以并行调用多个Python脚本,以便更好地利用多个内核。每个Python脚本都需要很长时间才能完成。

问题是如果我在Bash脚本中间按Ctrl + C,Python脚本实际上不会被杀死。我如何编写Bash脚本以便杀死它也会杀死所有后台的孩子?

这是我原来的“简化测试案例”。不幸的是,我似乎已经减少了太多,以至于它不再表现出问题;我的错误。

set -e

cat >work.py <<EOF
import sys, time
for i in range(10):
    time.sleep(1)
    print "Tick from", sys.argv[1]
EOF

function process {
    python ./work.py $1 &
}

process one
process two
wait

这是一个完整的测试案例,仍然大大减少,但希望这个将证明问题。它在我的机器上重现......但是,两天前,我认为旧的测试用例在我的机器上重现,今天肯定没有。

#!/bin/bash -e
set -x

cat >work.sh <<EOF
for i in 0 1 2 3 4 5 6 7 8 9; do
    sleep 1; echo "still going"
done
EOF
chmod +x work.sh

function kill_all_jobs { jobs -p | xargs kill; }
trap kill_all_jobs SIGINT

function process {
    ./work.sh $1
}

process one &
wait $!
echo "All done!"

即使在Ctrl + C之后,此代码仍继续打印still going。但是,如果我将&process移到内部(即:./work.sh $1 &),则Ctrl + C会按预期工作。我根本不明白这一点!

在我的真实脚本中,process包含多个命令,命令长时间运行,必须按顺序运行;所以我不知道在这种情况下如何“移动& process”。我确信它是可能的,但它必须是非平凡的。

$ bash --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12)
Copyright (C) 2007 Free Software Foundation, Inc.
编辑:非常感谢@AlanCurry教我一些Bash的东西。遗憾的是,我仍然不明白我的示例中到底发生了什么,但它实际上是一个没有实际意义的点,因为Alan 有帮助地指出,对于我的真实并行化问题,Bash是错误的工具,我应该使用make -j3的简单makefile! make尽可能并行运行,并且完全理解Ctrl + C;问题解决了(即使问题没有答案)。

2 个答案:

答案 0 :(得分:1)

我明白了!你所要做的就是摆脱那个python SIGINT处理程序。

cat >work.py <<'EOF'
import sys, time, signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
for i in range(10):
    time.sleep(1)
    print "Tick from", sys.argv[1]
EOF 
chmod +x work.py

function process {
    python ./work.py $1
}

process one &
wait $!
echo "All done!"

答案 1 :(得分:0)

trap对我好看:

$ bash --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)
Copyright (C) 2007 Free Software Foundation, Inc.

$ cat ./thang 
#! /bin/bash
set -e

cat >work.py <<EOF
import sys, time
for i in range(10):
  time.sleep(1)
  print "Tick from", sys.argv[1]
EOF

function process {
  python ./work.py $1 &
}

function killstuff {
  jobs -p | xargs kill
}

trap killstuff SIGINT

process one
process two
wait

$ ./thang 
Tick from one
Tick from two
Tick from one
Tick from two
^C$ ps aux | grep python | grep -v grep
$