2016-01-07 5 views
2

Использование подпроцесса и команды 'gnome-terminal -e bash' Я могу открыть гном-терминал по желанию (и закрепить его). Это делается либо сЗавершить гном-терминал, открытый с помощью подпроцесса

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

или

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

, но я не могу закрыть терминал, используя p.terminate() или p.kill(). Насколько я понимаю, это немного сложнее при использовании shell=True, но я не ожидал столкнуться с проблемами в противном случае.

ответ

2

Прекратить терминала и его детей (в той же группе процессов):

#!/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 является используется, чтобы избежать повторного использования активного терминала, чтобы мы могли убить вновь созданный терминал с помощью дескриптора subprocess
  • os.setpgrp ставит gnome-terminal в своей собственной группе процессов, так что os.killpg() может быть использован для передачи сигнала в эту группу
+0

Есть ли способ обойти это без '--disable-factory'? Я пытаюсь сделать это, возможно, работать с xterm, у которого нет опции '--disable-factory'. – Shatnerz

+0

@Shatnerz: Я не знаю, как работает 'xterm'. Вы можете задать отдельный вопрос о переполнении стека о случае xterm. – jfs

1

Вы должны быть в состоянии сделать это временное решение:

  • получить идентификатор процесса
  • убить процесс

Рабочий раствор: Закрыть гном-терминал-сервер

Как было предложено @ jf-sebastian в комментарии, gnome-terminal

просто отправляет запрос (до gnome-terminal-server), чтобы запустить новый терминал и немедленно выйти - нет ничего, чтобы убить процесс уже мертв (а вновь созданные процессы не являются потомками: новый процесс bash является дочерним по отношению к gnome-terminal-server , а не 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) 

Мое решение следовать этой логике:

  • запустить гном-терминал
  • получить последний Баш экземпляр открыт идентификатор процесса
  • убить этот идентификатор процесса

Наружные решения

Эти решения могут работать в более простых случаях:

Решение 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. Например.

В Windows, сигнал() может быть вызван только с SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV или 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, кажется, что лучший способ, чтобы закрыть экземпляр гном терминала будет выполнять команду Баш как:

killall -s {signal} gnome-terminal 

где {сигнал} имитирует Alt + F4.

Вы можете попробовать сделать это с помощью [pexpect]:

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

Я пытался именно то, что вы сказали в IPython терминале. Открытый терминал не был закрыт. – Shatnerz

+0

Думаю, я нашел его. Я отредактировал ответ, добавив идентификатор сессий и закрыв его с помощью os.killpg вместо os.kill. – mabe02

+0

Итак, это похоже на прогресс. Я могу скопировать и пропустить код точно. Терминал не появляется. Я предполагаю, что он немедленно уничтожен. Тем не менее, я добавляю 3-секундный сон, и терминал никогда не уничтожается даже при завершении скрипта. Похоже, что ничего не происходит, когда я пытаюсь использовать интерактивную оболочку python. – Shatnerz

Смежные вопросы