【问题标题】:stop shell script in background by sending signal通过发送信号在后台停止 shell 脚本
【发布时间】:2011-05-27 09:25:16
【问题描述】:

我有一个 bash shell 脚本 S1,它同步启动另一个 shell 脚本 S2(仅包含 sleep 20),即在前台。

我想要的是以下内容:

当我向S1 发送 SIGTERM 或 SIGINT 时,S1S2 都应该停止。

实际上,如果我在前台的命令行上启动 S1 并且如果我按下 CTRL-C(与我是否在脚本中显式捕获 SIGINT 无关),那么它会起作用。

当我在后台启动S1,然后用kill -s SIGINT $! 向它发送SIGINT 信号时,直到S2 终止其正常处理,即S2 没有被中断。

我的用例是后者,我需要一种方法来中断S1S2,只需向S1 发送信号。

【问题讨论】:

标签: bash signals


【解决方案1】:

S1.sh:

#!/bin/sh

on_term()
{
    echo "S1: Sending TERM to S2.sh"
    pkill -TERM S2.sh
    echo "S1: Waiting for S2 to complete..."
}

trap "on_term" TERM

echo "S1: Forking a child..."

./S2.sh &

while [ 1 == 1 ]; do
    wait
    if [ $? -eq 0 ]; then
        break
    fi
done

echo "S1: Done!"

S2.sh:

#!/bin/sh

on_term()
{
    echo "S2: Terminating..."
    exit -1
}

trap "on_term" TERM

echo "S2: Sleeping..."

sleep 5

echo "S2: Done!"

玩得开心!

【讨论】:

  • 您应该使用$! 而不是关闭任何具有特定名称的进程。
  • 当然,后台启动S2也是一种解决方案。但是我可以在不在后台启动 S2 的情况下达到同样的效果吗?为什么与我上面描述的行为不同(当 S1 在前台运行时 ctrl-c 与 S1 在后台启动时的“kill -s SIGINT”)?
【解决方案2】:

如果您从命令行启动 S1,则使用以 % 开头的作业规范将信号发送到进程组中的所有进程,例如 kill -INT %+

如果您从另一个脚本S3 开始S1,也许它应该以SIGINT 上的S1S2 终止,这可以简化为上述情况。否则,您可以尝试使用作业控制,如

set -m
S1 &
set +m
pid=$!
...
kill -INT -- -$pid

但这可能不适用于所有 shell,或者如果没有控制终端。像 Ilya 的回答那样手动转发信号是一种替代方法。

【讨论】:

    猜你喜欢
    • 2021-04-27
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多