Обработка прерывания клавиатуры при использовании подпроцесса
У меня есть python script, называемый monitiq_install.py
, который вызывает другие скрипты (или модули) с помощью модуля subprocess
python. Однако, если пользователь отправляет прерывание клавиатуры (CTRL + C), он выходит, но с исключением. Я хочу, чтобы он вышел, но приятно.
Мой код:
import os
import sys
from os import listdir
from os.path import isfile, join
from subprocess import Popen, PIPE
import json
# Run a module and capture output and exit code
def runModule(module):
try:
# Run Module
process = Popen(os.path.dirname(os.path.realpath(__file__)) + "/modules/" + module, shell=True, stdout=PIPE, bufsize=1)
for line in iter(process.stdout.readline, b''):
print line,
process.communicate()
exit_code = process.wait();
return exit_code;
except KeyboardInterrupt:
print "Got keyboard interupt!";
sys.exit(0);
Ошибка, которую я получаю, ниже:
python monitiq_install.py -a
Invalid module filename: create_db_user_v0_0_0.pyc
Not Running Module: '3parssh_install' as it is already installed
######################################
Running Module: 'create_db_user' Version: '0.0.3'
Choose username for Monitiq DB User [MONITIQ]
^CTraceback (most recent call last):
File "/opt/monitiq-universal/install/modules/create_db_user-v0_0_3.py", line 132, in <module>
inputVal = raw_input("");
Traceback (most recent call last):
File "monitiq_install.py", line 40, in <module>
KeyboardInterrupt
module_install.runModules();
File "/opt/monitiq-universal/install/module_install.py", line 86, in runModules
exit_code = runModule(module);
File "/opt/monitiq-universal/install/module_install.py", line 19, in runModule
for line in iter(process.stdout.readline, b''):
KeyboardInterrupt
Решение или некоторые указатели были бы полезны:)
- EDIT
С try catch
Running Module: 'create_db_user' Version: '0.0.0'
Choose username for Monitiq DB User [MONITIQ]
^CGot keyboard interupt!
Traceback (most recent call last):
File "monitiq_install.py", line 36, in <module>
module_install.runModules();
File "/opt/monitiq-universal/install/module_install.py", line 90, in runModules
exit_code = runModule(module);
File "/opt/monitiq-universal/install/module_install.py", line 29, in runModule
sys.exit(0);
NameError: global name 'sys' is not defined
Traceback (most recent call last):
File "/opt/monitiq-universal/install/modules/create_db_user-v0_0_0.py", line 132, in <module>
inputVal = raw_input("");
KeyboardInterrupt
Ответы
Ответ 1
Если вы нажмете Ctrl + C в терминале, то SIGINT будет отправлен всем процессам в группе процессов. См. дочерний процесс получает родительский SIGINT.
Вот почему вы видите трассировку из дочернего процесса, несмотря на try/except KeyboardInterrupt в родительском.
Вы можете подавить вывод stderr из дочернего процесса: stderr=DEVNULL
. Или запустите его в новой группе процессов: start_new_session=True
:
import sys
from subprocess import call
try:
call([sys.executable, 'child.py'], start_new_session=True)
except KeyboardInterrupt:
print('Ctrl C')
else:
print('no exception')
Если вы удалите start_new_session=True
в приведенном выше примере, тогда KeyboardInterrupt
также может быть поднят в дочернем элементе, и вы можете получить трассировку.
Если subprocess.DEVNULL
недоступен; вы можете использовать DEVNULL = open(os.devnull, 'r+b', 0)
. Если параметр start_new_session
недоступен; вы можете использовать preexec_fn=os.setsid
в POSIX.
Ответ 2
Вы можете сделать это, используя try и за исключением следующего:
import subprocess
try:
proc = subprocess.Popen("dir /S", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while proc.poll() is None:
print proc.stdout.readline()
except KeyboardInterrupt:
print "Got Keyboard interrupt"
Вы могли бы избежать shell=True
в своем исполнении в качестве лучшей практики безопасности.