当信号到来时,杀死bash脚本前景子节点

时间:2010-11-23 22:38:55

标签: linux bash scripting signals children

我在这样的bash脚本中包装一个fastcgi应用程序:

#!/bin/bash
# stuff
./fastcgi_bin
# stuff

由于bash仅在前台脚本结束时执行信号陷阱而不能kill -TERM scriptpid,因为fastcgi应用程序将保持活动状态。
我已经尝试将二进制文件发送到后台:

#!/bin/bash
# stuff
./fastcgi_bin &
PID=$!
trap "kill $PID" TERM
# stuff

但如果我这样做,显然stdin和stdout没有正确重定向,因为它没有与lighttpds mod_fastgi连接,前台版本确实有效。

编辑:我一直在关注这个问题,这是因为bash在后台启动程序时将/ dev / null重定向到stdin,所以任何避免这种情况的方法都应解决我的问题问题也是如此。

有关如何解决此问题的任何提示?

7 个答案:

答案 0 :(得分:15)

我想到了一些选择:

  • 从shell脚本启动进程时,两者都属于同一进程组。杀死父进程会让孩子们活着,所以应该杀死整个进程组。这可以通过将否定的PGID(进程组ID)传递给kill来实现,这与父进程的PID相同。 ej:kill -TERM -$PARENT_PID

  • 不要执行二进制文件 一个孩子,但更换脚本 exec进程。你失去了 事后能够执行的东西 但是,因为exec完全 替换父进程。

  • 不要杀死shell脚本进程,而是杀死FastCGI二进制文件。然后,在脚本中检查返回代码并相应地执行操作。例如:./fastcgi_bin || exit -1

根据mod_fastcgi处理工作进程的方式,只有第二个选项可行。

答案 1 :(得分:1)

我不知道这是否是你的选择,但是因为你有赏金我假设你可能会选择不在乎的想法。

你能在Pe​​rl中重写bash脚本吗? Perl有几种管理子进程的方法。您可以在核心模块perldoc perlipcIPC::Open2中阅读IPC::Open3及更多细节。

我不知道这将如何与lighttpd等接口,或者这种方法中是否有更多功能,但至少它为您提供了更多的灵活性,还有更多内容可供您阅读。

答案 2 :(得分:1)

我在几分钟前写了这个脚本来杀死一个bash脚本及其所有的孩子......

#!/bin/bash
# This script will kill all the child process id for a  given pid
# based on http://www.unix.com/unix-dummies-questions-answers/5245-script-kill-all-child-process-given-pid.html

ppid=$1

if [ -z $ppid ] ; then
   echo "This script kills the process identified by pid, and all of its kids";
   echo "Usage: $0 pid";
   exit;
fi

for i in `ps j | awk '$3 == '$ppid' { print $2 }'`
do
    $0 $i   
    kill -9 $i
done

确保脚本可执行,否则您将在$ 0 $ i

上收到错误消息

答案 3 :(得分:0)

我不确定我是否完全明白你的意思,但这是我尝试过的,而且这个过程似乎能够管理陷阱(称之为trap.sh):

#!/bin/bash

trap "echo trap activated" TERM INT
echo begin
time sleep 60
echo end

启动它:

./trap.sh &

并使用它(一次只能执行其中一个命令):

kill -9 %1
kill -15 %1

或从前景开始:

./trap.sh

用control-C中断。

似乎适合我。 究竟什么对你不起作用?

答案 4 :(得分:0)

您可以通过自己重定向stdin来覆盖后台进程的隐式</dev/null,例如:

sh -c 'exec 3<&0; { read x; echo "[$x]"; } <&3 3<&- & exec 3<&-; wait'

答案 5 :(得分:0)

尝试使用stdin保留原始./fastcgi_bin 0<&0 &

#!/bin/bash
# stuff
./fastcgi_bin 0<&0 &
PID=$!./fastcgi_bin 0<&0 &
trap "kill $PID" TERM
# stuff


# test
#sh -c 'sleep 10 & lsof -p ${!}'
#sh -c 'sleep 10 0<&0 & lsof -p ${!}'

答案 6 :(得分:-1)

您可以使用coprocess

执行此操作

编辑:好吧,coprocesses是可以打开stdin和stdout的后台进程(因为bash为它们准备了fifos)。但是你仍然需要读取/写入那些fifos,而唯一有用的原语是bash的read(可能带有超时或文件描述符);没有足够强大的cgi。所以在第二个想法,我的建议是不要在bash中做这件事。在fastcgi或WSGI等http包装器中做额外的工作会更方便。