从bash脚本执行的Python脚本未处理信号

时间:2019-07-30 15:16:29

标签: python bash shell

问题:从命令行执行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秒钟,将“垂死”发布到stdout,然后退出)

但是,如果从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脚本调用时也能正确处理信号?

1 个答案:

答案 0 :(得分:1)

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

#!/bin/bash

./sigterm_tester.py &

child=$(pgrep -P $$)

#DEBUGONLY
sleep 2

kill -15 $child

while true;
do
        sleep 1
done