首页 > 解决方案 > 从 bash 脚本调用的 Python 脚本不处理信号

问题描述

问题:从命令行执行 python 脚本时,它按预期捕获并处理 SIGTERM 信号。但是,如果脚本由 bash 脚本调用,然后 bash 脚本将信号发送到 python 脚本,则它不会按预期处理 SIGTERM 信号。

有问题的python脚本非常简单:它等待一个SIGTERM,然后等待几秒钟然后退出。

    #!/usr/bin/env python3

    import sys
    import signal
    import time


    # signal handler
    def sigterm_handler(signal, frame):
        time.sleep(5)
        print("dying")
        sys.exit()

    # register the signal handler
    signal.signal(signal.SIGTERM, sigterm_handler)


    while True:
        time.sleep(1)

如果这是直接调用然后从命令行发送的信号即

> ./sigterm_tester.py &
> kill -15 <PID>

信号处理正常执行(它等待 5 秒,将“垂死”发布到标准输出,然后退出)

但是,如果改为从 bash 脚本调用它,它似乎不再捕获 SIGTERM 而是立即退出。这个简单的 bash 脚本执行 python 脚本,然后杀死它的子脚本(python 脚本)。但是,终止立即发生,而不是在 5 秒延迟后发生,并且没有将“垂死”打印到 stdout(或当我尝试 stdout 重定向时打印到文件)。


    #!/bin/bash

    ./sigterm_tester.py &

    child=$(pgrep -P $$)

    kill -15 $child

    while true;
    do
        sleep 1
    done

一些附加信息:我还用 sh 和 bash 对此进行了测试,并且发生了相同的行为。此外,我已经对此进行了测试,并在 MacOS 环境和 Linux 环境中获得了相同的行为。我还用 python2 和 python3 测试了它。

我的问题是为什么行为看起来不同取决于程序的调用方式,有没有办法确保 python 程序即使在从 bash 脚本调用时也能正确处理信号?

标签: pythonbashshell

解决方案


总结@Matt Walck 的评论。在 bash 脚本中,您在调用它后立即杀死了 python 进程,这可能没有足够的时间在 sigterm 信号上注册。在 spawn 和 kill 命令之间添加一个sleep命令将支持该理论。

#!/bin/bash

./sigterm_tester.py &

child=$(pgrep -P $$)

#DEBUGONLY
sleep 2

kill -15 $child

while true;
do
        sleep 1
done

推荐阅读