在cmd.Cmd命令行解释器中更好地处理KeyboardInterrupt
在使用Python的cmd.Cmd模块创建自定义命令行界面时,我该如何让处理程序中止当前输入并给我一个新的提示符呢?
这里有一个简单的例子:
# console_min.py
# run: 'python console_min.py'
import cmd, signal
class Console(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self)
self.prompt = "[test] "
signal.signal(signal.SIGINT, handler)
def do_exit(self, args):
return -1
def do_EOF(self, args):
return self.do_exit(args)
def preloop(self):
cmd.Cmd.preloop(self)
self._hist = []
self._locals = {}
self._globals = {}
def postloop(self):
cmd.Cmd.postloop(self)
print "Exiting ..."
def precmd(self, line):
self._hist += [ line.strip() ]
return line
def postcmd(self, stop, line):
return stop
def emptyline(self):
return cmd.Cmd.emptyline(self)
def handler(self, signum, frame):
# self.emptyline() does not work here
# return cmd.Cmd.emptyline(self) does not work here
print "caught ctrl+c, press return to continue"
if __name__ == '__main__':
console = Console()
console.cmdloop()
如果能提供更多帮助,我将非常感激。
原始问题和更多细节: [目前下面的建议已经整合到这个问题中——仍在寻找答案。更新以修正一个错误。]
我尝试将处理程序移动到循环外的一个函数中,以看看这样是否更灵活,但似乎并没有。
我正在使用Python的cmd.Cmd模块来创建自己的命令行解释器,以便与一些软件进行交互。我经常按下ctrl+c,期待像常见的shell那样返回一个新的提示符,而不执行我输入的命令。然而,它只是退出了。我尝试在代码的不同位置(如preloop等)捕获KeyboardInterrupt异常,但没有成功。我读了一些关于sigint的内容,但不太清楚这在这里如何适用。
更新:根据下面的建议,我尝试实现信号处理,现在ctrl+c不会退出命令行界面,而是打印出一条消息。然而,我的新问题是,我似乎无法让处理函数(见下文)做太多事情,除了打印。我希望ctrl+c基本上能中止当前输入并给我一个新的提示符。
8 个回答
你可以用一个叫做CTRL-C信号的东西来控制程序的停止,这个信号可以通过信号处理器来捕捉。如果你加上下面的代码,程序在你按CTRL-C的时候就不会退出了:
import signal
def handler(signum, frame):
print 'Caught CTRL-C, press enter to continue'
signal.signal(signal.SIGINT, handler)
如果你不想在每次按CTRL-C后都按ENTER,只需要让处理器什么都不做,这样就能捕捉到这个信号,但不会有任何效果:
def handler(signum, frame):
""" just do nothing """
与其使用信号处理,不如直接捕捉 cmd.Cmd.cmdloop()
抛出的 KeyboardInterrupt
。当然,你可以使用信号处理,但这并不是必须的。
可以在一个循环里运行 cmdloop()
,当遇到 KeyboardInterrupt
异常时,循环会重新开始,但如果遇到文件结束符(EOF),则会正常结束。
import cmd
import sys
class Console(cmd.Cmd):
def do_EOF(self,line):
return True
def do_foo(self,line):
print "In foo"
def do_bar(self,line):
print "In bar"
def cmdloop_with_keyboard_interrupt(self):
doQuit = False
while doQuit != True:
try:
self.cmdloop()
doQuit = True
except KeyboardInterrupt:
sys.stdout.write('\n')
console = Console()
console.cmdloop_with_keyboard_interrupt()
print 'Done!'
按下 CTRL-c 只是会在新的一行打印一个新的提示符。
(Cmd) help
Undocumented commands:
======================
EOF bar foo help
(Cmd) <----- ctrl-c pressed
(Cmd) <------ctrl-c pressed
(Cmd) ddasfjdfaslkdsafjkasdfjklsadfljk <---- ctrl-c pressed
(Cmd)
(Cmd) bar
In bar
(Cmd) ^DDone!
我现在正在用Cmd模块创建一个命令行界面。遇到了同样的问题,不过我找到了解决办法。
以下是代码:
class Shell(Cmd, object)
...
def cmdloop(self, intro=None):
print(self.intro)
while True:
try:
super(Shell, self).cmdloop(intro="")
break
except KeyboardInterrupt:
print("^C")
...
现在你在这个命令行界面里有了一个合适的键盘中断处理器,也就是按下CTRL-C时的处理方式。