【问题标题】:How to send signals from a backgrounded process using pexpect如何使用 pexpect 从后台进程发送信号
【发布时间】:2014-09-17 21:17:55
【问题描述】:

使用python3/linux/bash:

gnr@localhost: cat my_script
#!/usr/bin/python3
import time, pexpect

p = pexpect.spawn('sleep 123')
p.sendintr()
time.sleep(1000)

按原样运行时效果很好(即my_script 启动一个sleep 123 子进程,然后发送一个SIGINT 杀死sleep 123)。但是,当我将my_script 作为孙进程的背景时,它不再能够杀死sleep 123 命令:

gnr@localhost: (my_script &> /dev/null &)

任何人都知道这里发生了什么/如何更改my_scriptpexpect 以仍然能够将SIGINT 发送到它的子进程?

我认为这与背景有关导致没有控制终端,也许我需要创建一个新的 pty?

更新:从未想过如何创建 pty(尽管使用 -t 选项 ssh'ing 到 localhost 有效) - 最终执行 os.fork() 来后台子进程而不是 (my_script &> /dev/null &) 有效因为(我猜)控制终端没有立即关闭。

【问题讨论】:

    标签: python linux bash signals pexpect


    【解决方案1】:

    你确定进程没有被杀死吗?我希望它在进程列表中显示<defunct>,因为生成的进程现在位于sleep 中,并且在sleep 完成之前无法完成正确的清理。 <defunct> 进程已被杀死,只是它们的父进程没有进行清理。

    如果您可以以某种方式修改您的代码,以便父级实际上经过正常处理并关闭子级(生成),那么它应该可以工作。虽然很笨拙,但这可能会奏效:

    import time, pexpect, os
    
    newpid = os.fork()
    if newpid == 0:
        # Child
        p = pexpect.spawn('sleep 123')
        p.sendintr()
    else:
        # parent
        time.sleep(1000)
    

    在这种情况下,我们fork我们自己的孩子负责处理生成并进行杀戮。由于我们的孩子不会自己阻塞sleep,它会优雅地退出,其中包括正确清理它杀死的进程。与此同时,主(父)线程正在等待sleep

    在您发表评论后,我突然想到,虽然我在 bash 提示符下将脚本置于后台,但我的做法与您的不同。

    我正在使用

    (expecttest.py > /dev/null 2>&1 &)
    

    这会将标准输入和标准输出重定向到 >/dev/null 并将进程置于后台。

    如果我采用您的原始代码,而不是执行 sendintr,而是使用您从命令 shell 中的调用执行 terminate,它就可以工作。在这种情况下,sleep 123 似乎没有响应 pexpect 正在做什么。

    【讨论】:

    • 是的,我确定它还活着——我尝试运行你的代码,但我最终得到了 2 个my_script 进程和一个sleep 123 进程——这也是如果我运行@ 987654335@ 为(my_script &> /dev/null &)
    • 我认为这是在正确的轨道上,我一直在尝试pty.fork()pty.openpty() 虽然还没有弄清楚
    • 我修改了我的答案。运行我的脚本时,我把它放在后台略有不同。
    • 谢谢,但不幸的是我也不能使用 terminate() - 正在运行而不是 sleep 123 的真实程序有不同的用户(通过一点 sudo 魔法),所以发送它 @987654340 @ 不是一个选项。
    • 啊,好吧,这个细节会改变一切。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-06
    • 1970-01-01
    • 2018-08-23
    • 2017-07-11
    • 1970-01-01
    相关资源
    最近更新 更多