当信号到来时杀死 bash 脚本前台子进程

发布于 2024-10-03 21:41:38 字数 544 浏览 4 评论 0原文

我将 fastcgi 应用程序包装在 bash 脚本中,如下所示:

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

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

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

但是如果我这样做,显然标准输入和标准输出没有正确重定向,因为它没有与lighttpds mod_fastgi连接,前台版本确实可以工作。

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

关于如何解决这个问题有任何提示吗?

I am wrapping a fastcgi app in a bash script like this:

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

As bash only executes traps for signals when the foreground script ends I can't just kill -TERM scriptpid because the fastcgi app will be kept alive.
I've tried sending the binary to the background:

#!/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.

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.

Any hint on how to solve this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

等你爱我 2024-10-10 21:41:38

我想到了一些选项:

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

  • 不要执行二进制文件
    一个孩子,但替换了脚本
    使用exec 进行处理。你失去了
    之后执行事情的能力
    不过,因为 exec 完全
    替换父进程。

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

根据 mod_fastcgi 如何处理工作进程,只有第二个选项可能是可行的。

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_PID

  • Do not execute the binary as
    a child, but replacing the script
    process with exec. You lose the
    ability to execute stuff afterwards
    though, because exec completely
    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

Depending on how mod_fastcgi handles worker processes, only the second option might be viable.

裂开嘴轻声笑有多痛 2024-10-10 21:41:38

我几分钟前写了这个脚本来杀死一个 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 上收到错误

I wrote this script just minutes ago to kill a bash script and all of its children...

#!/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

Make sure the script is executable, or you will get an error on the $0 $i

贱贱哒 2024-10-10 21:41:38

我不知道这是否适合您,但由于您有赏金,我假设您可能会寻求跳出框框的想法。

你能用 Perl 重写 bash 脚本吗? Perl 有多种管理子进程的方法。您可以阅读 perldoc perlipc 以及核心模块中的更多详细信息IPC::Open2IPC::Open3

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

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 perlipc and more specifics in the core modules IPC::Open2 and 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.

野鹿林 2024-10-10 21:41:38

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

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

You can override the implicit </dev/null for a background process by redirecting stdin yourself, for example:

sh -c 'exec 3<&0; { read x; echo "[$x]"; } <&3 3<&- & exec 3<&-; wait'
你在看孤独的风景 2024-10-10 21:41:38

我不确定我完全明白你的意思,但这是我尝试过的,该过程似乎能够管理陷阱(称之为 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 中断。

似乎对我有用。
到底什么对你不起作用?

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):

#!/bin/bash

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

Start it:

./trap.sh &

And play with it (only one of those commands at once):

kill -9 %1
kill -15 %1

Or start in foreground:

./trap.sh

And interrupt with control-C.

Seems to work for me.
What exactly does not work for you?

骑趴 2024-10-10 21:41:38

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

#!/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 ${!}'

Try keeping the original stdin using ./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 ${!}'
无语# 2024-10-10 21:41:38

您可以使用协进程来做到这一点。

编辑:嗯,协进程是可以打开 stdin 和 stdout 的后台进程(因为 bash 为它们准备了 fifo)。但是您仍然需要读/写这些 fifo,唯一有用的原语是 bash 的 read(可能带有超时或文件描述符);对于 cgi 来说,没有什么足够强大的。所以再想一想,我的建议是不要在 bash 中做这件事。在 fastcgi 或像 WSGI 这样的 http 包装器中完成额外的工作会更方便。

You can do that with a 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文