使用子进程时处理键盘中断 [英] Handling keyboard interrupt when using subproccess

查看:37
本文介绍了使用子进程时处理键盘中断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆