有信号时杀死 bash 脚本前台子进程
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4261726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Kill bash script foreground children when a signal comes
提问by Arkaitz Jimenez
I am wrapping a fastcgi app in a bash script like this:
我将一个 fastcgi 应用程序包装在一个 bash 脚本中,如下所示:
#!/bin/bash
# stuff
./fastcgi_bin
# stuff
As bash only executes traps for signals when the foreground script ends I can't just kill -TERM scriptpidbecause the fastcgi app will be kept alive.
I've tried sending the binary to the background:
由于 bash 仅在前台脚本结束时执行信号陷阱,我不能仅仅kill -TERM scriptpid因为 fastcgi 应用程序将保持活动状态。
我试过将二进制文件发送到后台:
#!/bin/bash
# stuff
./fastcgi_bin &
PID=$!
trap "kill $PID" TERM
# stuff
But if I do it like this, apparently the stdin and stdout aren't properly redirected because it does not connect with lighttpds mod_fastgi, the foreground version does work.
但是如果我这样做,显然 stdin 和 stdout 没有正确重定向,因为它没有与 lighttpds mod_fastgi 连接,前台版本确实可以工作。
EDIT:I've been looking at the problem and this happens because bash redirects /dev/null to stdin when a program is launched in the background, so any way of avoiding this should solve my problem as well.
编辑:我一直在研究这个问题,这是因为当程序在后台启动时 bash 将 /dev/null 重定向到 stdin,所以任何避免这种情况的方法也应该可以解决我的问题。
Any hint on how to solve this?
有关如何解决此问题的任何提示?
回答by kovan
There are some options that come to my mind:
我想到了一些选择:
When a process is launched from a shell script, both belong to the same process group. Killing the parent process leaves the children alive, so the whole process group should be killed. This can be achieved by passing the negated PGID (Process Group ID) to kill, which is the same as the parent's PID. ej:
kill -TERM -$PARENT_PIDDo not execute the binary as a child, but replacing the script process with
exec. You lose the ability to execute stuff afterwards though, becauseexeccompletely replaces the parent process.Do not kill the shell script process, but the FastCGI binary. Then, in the script, examine the return code and act accordingly. e.g:
./fastcgi_bin || exit -1
当一个进程从 shell 脚本启动时,它们都属于同一个进程组。杀死父进程会使子进程活着,因此应该杀死整个进程组。这可以通过将取反的PGID(进程组ID)传递给kill来实现,与父进程的PID相同。ej:
kill -TERM -$PARENT_PID不要将二进制文件作为子进程执行,而是将脚本进程替换为
exec. 但是,您将失去之后执行内容的能力,因为exec完全取代了父进程。不要杀死 shell 脚本进程,而是杀死 FastCGI 二进制文件。然后,在脚本中,检查返回代码并采取相应的行动。例如:
./fastcgi_bin || exit -1
Depending on how mod_fastcgi handles worker processes, only the second option might be viable.
根据 mod_fastcgi 处理工作进程的方式,只有第二个选项可能是可行的。
回答by Andre
I wrote this script just minutes ago to kill a bash script and all of its children...
几分钟前我写了这个脚本来杀死一个 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=
if [ -z $ppid ] ; then
echo "This script kills the process identified by pid, and all of its kids";
echo "Usage: #!/bin/bash
trap "echo trap activated" TERM INT
echo begin
time sleep 60
echo end
pid";
exit;
fi
for i in `ps j | awk ' == '$ppid' { print }'`
do
./trap.sh &
$i
kill -9 $i
done
Make sure the script is executable, or you will get an error on the $0 $i
确保脚本是可执行的,否则你会在 $0 $i 上得到一个错误
回答by Joel Berger
I have no idea if this is an option for you or not, but since you have a bounty I am assuming you might go for ideas that are outside the box.
我不知道这是否适合您,但由于您有赏金,我假设您可能会寻求框外的想法。
Could you rewrite the bash script in Perl? Perl has several methods of managing child processes. You can read perldoc perlipcand more specifics in the core modules IPC::Open2and IPC::Open3.
你能用 Perl 重写 bash 脚本吗?Perl 有多种管理子进程的方法。您可以perldoc perlipc在核心模块IPC::Open2和IPC::Open3.
I don't know how this will interface with lighttpd etc or if there is more functionality in this approach, but at least it gives you some more flexibility and some more to read in your hunt.
我不知道这将如何与 lighttpd 等交互,或者这种方法是否有更多功能,但至少它为您提供了更多灵活性和更多阅读内容。
回答by asoundmove
I'm not sure I fully get your point, but here's what I tried and the process seems to be able to manage the trap (call it trap.sh):
我不确定我是否完全明白你的意思,但这是我尝试过的,这个过程似乎能够管理陷阱(称之为 trap.sh):
kill -9 %1
kill -15 %1
Start it:
启动它:
./trap.sh
And play with it (only one of those commands at once):
并使用它(一次只能使用其中一个命令):
sh -c 'exec 3<&0; { read x; echo "[$x]"; } <&3 3<&- & exec 3<&-; wait'
Or start in foreground:
或者从前台开始:
#!/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 ${!}'
And interrupt with control-C.
并用 control-C 中断。
Seems to work for me. What exactly does not work for you?
似乎对我有用。什么对你不起作用?
回答by jilles
You can override the implicit </dev/nullfor a background process by redirecting stdin yourself, for example:
您可以</dev/null通过自己重定向 stdin来覆盖后台进程的隐式,例如:
回答by nadx
Try keeping the original stdinusing ./fastcgi_bin 0<&0 &:
尝试stdin使用./fastcgi_bin 0<&0 &以下方法保留原始文件:
回答by Tobu
You can do that with a coprocess.
你可以用coprocess做到这一点。
Edit: well, coprocesses are background processes that can have stdin and stdout open (because bash prepares fifos for them). But you still need to read/write to those fifos, and the only useful primitive for that is bash's read(possibly with a timeout or a file descriptor); nothing robust enough for a cgi. So on second thought, my advice would be not to do this thing in bash. Doing the extra work in the fastcgi, or in an http wrapper like WSGI, would be more convenient.
编辑:好吧,协进程是可以打开 stdin 和 stdout 的后台进程(因为 bash 为它们准备了 fifos)。但是你仍然需要读/写这些 fifo,唯一有用的原语是 bash read(可能带有超时或文件描述符);对于 cgi 来说,没有什么足够强大的了。所以再想一想,我的建议是不要在 bash 中做这件事。在 fastcgi 或像 WSGI 这样的 http 包装器中做额外的工作会更方便。

