Python 终止使用子进程打开的gnome终端

Python 终止使用子进程打开的gnome终端,python,terminal,subprocess,Python,Terminal,Subprocess,使用子流程和命令“gnome-terminal-ebash”,我可以根据需要打开一个gnome终端(并让它保持不变)。这两种方法都可以完成 p=subprocess.Popen(['gnome-terminal', '-e', 'bash']) 或 但是我无法使用p.terminate()或p.kill()关闭终端。据我所知,在使用shell=True时,这有点棘手,但我没想到在其他情况下会遇到问题。您应该能够解决此问题: 获取进程id 终止进程 工作解决方案:关闭gnome终端服务器 正

使用子流程和命令“
gnome-terminal-ebash
”,我可以根据需要打开一个gnome终端(并让它保持不变)。这两种方法都可以完成

p=subprocess.Popen(['gnome-terminal', '-e', 'bash'])


但是我无法使用
p.terminate()
p.kill()
关闭终端。据我所知,在使用
shell=True
时,这有点棘手,但我没想到在其他情况下会遇到问题。

您应该能够解决此问题:

  • 获取进程id
  • 终止进程
工作解决方案:关闭gnome终端服务器

正如@j-f-sebastian在评论中所建议的,gnome终端

只需发送请求(到
gnome终端服务器
)启动一个新终端并立即退出——没有什么可以杀死的进程已经死了(并且新创建的进程不是后代:新的
bash
进程是
gnome终端服务器
的子进程,而不是
gnome终端

我的解决方案遵循以下逻辑:

  • 运行gnome终端
  • 获取最新的bash实例打开的进程id
  • 终止此进程id
破碎的解决方案

这些解决方案可能适用于更简单的情况:

解决方案1

import subprocess
import os, signal

p=subprocess.Popen(['gnome-terminal -e bash'], shell=True)
p_pid = p.pid  # get the process id
os.kill(p_pid, signal.SIGKILL)
为了选择合适的信号传递方法而不是SIGKILL,您可以参考。例如

在Windows上,只能使用SIGABRT、SIGFPE、SIGILL、SIGINT、SIGSEGV或SIGTERM调用signal()

对于Unix,您有一个相当广泛的方法列表可供调用

要更好地了解os.kill,请参考

解决方案2

对Unix有用的另一种方法可以是:

import subprocess
import os, signal

p=subprocess.Popen(['gnome-terminal -e bash'], stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
os.killpg(os.getpgid(p.pid), signal.SIGTERM)
似乎您的进程正在打开阻止父进程关闭的子进程。向父进程添加一个,您应该能够修复它

解决方案3

import subprocess, psutil

def kill(p_pid):
    process = psutil.Process(p_pid)
    for proc in process.get_children(recursive=True):
        proc.kill()
    process.kill()

p = subprocess.Popen(['gnome-terminal -e bash'], shell=True)
try:
    p.wait(timeout=3)
except subprocess.TimeoutExpired:
    kill(p.pid)
这个解决方案需要一个新的解决方案

解决方案4

根据,关闭gnome终端实例的最佳方法似乎是执行bash命令,如:

killall -s {signal} gnome-terminal
其中{signal}模拟Alt+F4

您可以尝试使用[pexpect]执行此操作:

p = pexpect.spawn(your_cmd_here)
p.send('^F4')

要终止终端及其子级(在同一进程组中),请执行以下操作:

  • --disable factory
    用于避免重新使用活动终端,以便我们可以通过
    子进程
    句柄杀死新创建的终端
  • os.setpgrp
    gnome终端
    放在自己的进程组中,以便可以使用
    os.killpg()
    向该组发送信号

我完全按照你在ipython终端上说的做了。打开的候机楼没有关。我想我找到了。我编辑了答案,添加了会话id,并使用os.killpg而不是os.killSo关闭了会话,这看起来有进步。我能准确地复制并通过代码。没有终端弹出。我想它马上就被摧毁了。但是,我添加了3秒钟的睡眠,即使在脚本完成时,终端也不会被破坏。当我尝试使用交互式python外壳时,似乎什么都没有发生。另一个选项可能是使用。我会在答案中再写一个例子,这样你就可以试一试了!否决票。所有解决方案都不适用于
gnome终端
。在我的系统上,
gnome终端
是一个启动应用程序,它不等待实际的终端退出:它只发送请求(到
gnome终端服务器
),启动一个新的终端并立即退出——没有什么可以阻止进程已经死亡(新创建的进程不是子进程:新的
bash
进程是
gnome终端服务器的子进程,而不是
gnome终端的子进程)。有没有办法不用
--禁用工厂
?我正在尝试让它可以选择性地与xterm一起工作,而xterm没有
--禁用工厂
选项。@Shatnerz:我不知道
xterm
是如何工作的。你可以专门询问一个关于
xterm
案例的堆栈溢出问题。只是更新:--禁用工厂不再受支持,至少从3.28.2版开始。我仍然对这个问题的答案感兴趣,因为这个解决方案对我不起作用!@JamesPaulMason:答案中的代码在我的带有GNOME终端3.28.2的Ubuntu机器上运行。只是在两个不同的系统上进行了尝试。它在带有GNOME终端3.18.3 b的Ubuntu上运行ut不使用gnome终端3.28.2,使用VTE 0.52.2+GNUTLS_(ツ)_/¯
killall -s {signal} gnome-terminal
p = pexpect.spawn(your_cmd_here)
p.send('^F4')
#!/usr/bin/env python
import os
import signal
import subprocess

p = subprocess.Popen(['gnome-terminal', '--disable-factory', '-e', 'bash'],
                     preexec_fn=os.setpgrp)
# do something here...
os.killpg(p.pid, signal.SIGINT)