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

Terminate a gnome-terminal opened with subprocess

使用子进程和命令“gnome-terminal -e bash”我可以根据需要打开一个 gnome 终端(并保留它)。这是通过

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

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

但我无法使用 p.terminate()p.kill() 关闭终端。据我了解,这在使用 shell=True 时有点棘手,但我没想到会 运行 否则会出现问题。

您应该可以解决此问题:

  • 获取进程ID
  • 终止进程

有效解决方案:关闭gnome-terminal-server

正如评论中@j-f-sebastian所建议的那样,gnome-terminal

just sends the request (to gnome-terminal-server) to start a new terminal and exits immediately -- there is nothing to kill the process is already dead (and newly created processes are not descendants:  the new bash process is a child of gnome-terminal-server, not gnome-terminal).

import subprocess
import os, signal
import time

p=subprocess.Popen(['gnome-terminal -e bash'], stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
print "this is going to be closed in 3 sec"
time.sleep(3)
# this line returns the list of bash instances pid as string
bash_pids = subprocess.check_output(["pidof", "bash"])
# I get the last instance opened
pid_to_kill = bash_pids.split(" ")[0]
os.kill(int(pid_to_kill), signal.SIGTERM)

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

  • 运行 gnome-terminal
  • 获取最新的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可以参考signal documentation。例如

On Windows, signal() can only be called with SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, or SIGTERM

对于 Unix,您有相当多的方法可以调用。

为了更好地了解os.kill,您可以参考its documentation.

解决方案 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)

您的进程似乎正在打开阻止父进程关闭的子进程。将 session id 添加到您的父进程,您应该能够修复它。

解决方案 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)

此解决方案需要 psutil.

解决方案 4

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

killall -s {signal} gnome-terminal

其中 {signal} 模拟 Alt + F4。

您可以尝试使用 [pexpect]:

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)
  • --disable-factory 用于避免 re-using 活动终端,以便我们可以通过 subprocess 句柄
  • 终止新创建的终端
  • os.setpgrpgnome-terminal 放入其自己的进程组中,以便 os.killpg() 可用于向该组发送信号