使用子进程时处理键盘中断 [英] Handling keyboard interrupt when using subproccess
问题描述
我有一个名为 monitiq_install.py
的 python 脚本,它使用 subprocess
python 模块调用其他脚本(或模块).但是,如果用户发送键盘中断 (CTRL + C),它会退出,但有一个例外.我希望它退出,但很好.
I have python script called monitiq_install.py
which calls other scripts (or modules) using the subprocess
python module. However, if the user sends a keyboard interrupt (CTRL + C) it exits, but with an exception. I want it to exit, but nicely.
我的代码:
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
一个解决方案或一些指针会有所帮助:)
A solution or some pointers would be helpful :)
--编辑使用 try catch
--EDIT With 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
推荐答案
如果您在终端中按 Ctrl + C,那么 SIGINT 将发送到进程组中的所有进程.请参阅子进程接收父进程的 SIGINT.
If you press Ctrl + C in a terminal then SIGINT is sent to all processes within the process group. See child process receives parent's SIGINT.
这就是为什么尽管在父进程中有 try/except KeyboardInterrupt,您仍会看到来自子进程的回溯.
That is why you see the traceback from the child process despite try/except KeyboardInterrupt in the parent.
您可以抑制子进程的 stderr 输出:stderr=DEVNULL
.或者在一个新的进程组中启动它:start_new_session=True
:
You could suppress the stderr output from the child process: stderr=DEVNULL
. Or start it in a new process group: 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
也可能在子进程中引发,你可能会得到回溯.
If you remove start_new_session=True
in the above example then KeyboardInterrupt
may be raised in the child too and you might get the traceback.
如果 subprocess.DEVNULL
不可用;你可以使用 DEVNULL = open(os.devnull, 'r+b', 0)
.如果 start_new_session
参数不可用;您可以在 POSIX 上使用 preexec_fn=os.setsid
.
If subprocess.DEVNULL
is not available; you could use DEVNULL = open(os.devnull, 'r+b', 0)
. If start_new_session
parameter is not available; you could use preexec_fn=os.setsid
on POSIX.
这篇关于使用子进程时处理键盘中断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!