文章目录
- 1. 简介
- 2. cmd的主要方法和属性
- 3. 其他说明
- 4. 综合案例1
- 5. 综合案例2
1. 简介
cmd模块为命令行接口(command-line interfaces, CLI)提供了一个简单的框架,可以在自己的程序中使用它来创建自己的命令行程序。
cmd模块是python中包含的一个公共模块,用于交互式shell和其它命令解释器等的基类。我们可以基于cmd模块自定义我们的子类,实现我们自己的交互式shell。
它的执行流程也挺简单的,使用命令行解释器循环读取输入的所有行并解析它们,然后把输入行交给命令处理器来处理。命令行处理器接收并解析输入行,这里先需要知道输入行包括两个部分:命令和参数。通过继承和子类方法重载父类方法的特性,命令行处理器找到适合处理该命令的子类方法。
比如我们输入的是hello baby,那么我们就重写名为do_hello的函数。倘若处理方法返回True,则直接退出循环。
简单代码示例:
from cmd import Cmd
import os
import sys
class Cli(Cmd):
def __init(self):
Cmd.__init__(self)
def do_hello(self,line):
print "hello",line
if __name__ == '__main__':
cli = Cli()
cli.cmdloop()
输出:
2. cmd的主要方法和属性
- 方法:
(1)cmdloop():类似与Tkinter的mainloop,运行Cmd解析器;
(2)onecmd(str):读取输入,并进行处理,通常不需要重载该函数,而是使用更加具体的do_command来执行特定的命令;
(3)emptyline():当输入空行时调用该方法;
(4)default(line):当无法识别输入的command时调用该方法;
(5)completedefault(text,line,begidx,endidx):如果不存在针对的complete_*()方法,那么会调用该函数,该函数主要是用于tab补充,且只能在linux下使用。
(6)precmd(line):命令line解析之前被调用该方法;
(7)postcmd(stop,line):命令line解析之后被调用该方法;
(8)preloop():cmdloop()运行之前调用该方法;
(9)postloop():cmdloop()退出之后调用该方法;
(10)help_command():对command命令的说明,其中command为可变字符
- 属性:
(1)prompt:交互式提示字符,也就是刚才的(Cmd)可以换成我们自己想要的字符
(2)intro:在进入交互式shell前输出的字符串,可以认定为标志语之类的。其实这个可以在preloop方法输出也是一样的
- 注意
以do_和help_开头的函数的作用(do_ * 开头为命令,执行的名令,以help_ * 开头的为帮助,对应命令的帮助说明) - 代码示例
from cmd import Cmd
class BingCmd(Cmd):
"""just try try"""
prompt = "BingCmd>"
intro = "Welcome to BingCMD"
# 在cmd.Cmd派生类中,以do_ * 开头为命令,以help_ * 开头的为帮助
def print_log(self, argv):
print("la la la ")
def do_bing(self, argv):
self.print_log(argv)
def help_bing(self):
print("just print la la la")
def do_hu(self, argv):
print("调用hu功能")
def help_hu(self):
print("输出hu")
def do_exit(self, argv):
# 处理方法返回True,则直接退出循环。
print("exit()")
return True
def help_exit(self):
print("用来退出")
def preloop(self):
print("cmdloop()运行之前调用该方法")
def postloop(self):
print("cmdloop()退出之后调用该方法")
if __name__ == "__main__":
BingCmd().cmdloop()
输出结果:
3. 其他说明
- 当输入空行的时候,我们可以重载emptyline()来处理:
def emptyline(self):
print 'please input command!'
- 自定义我们自己的交互式提示字符串
prompt = 'pyFun>'
- 自定义我们的欢迎语:
intro = 'Welcom to pyFun!'
- 使程序能够正常接收ctrl+c的退出方式
try:
os.system('cls')
client = Client()
client.cmdloop()
except:
exit()
在我按下ctrl+c之后能够正常退出不报错
- 当输入无法识别的命令时,使用default(line)来处理
4. 综合案例1
# coding=utf-8
from cmd import *
import sys
class TestCmd(Cmd):
def __init__(self):
Cmd.__init__(self)
Cmd.intro="测试用的模块"
def do_test1(self,line):
print "test模块下的test命令"
def help_test1(self):
print "用于测试这个模块"
def preloop(self):
print u"进入test模块"
def postloop(self):
print u"退出test模块"
def do_exit(self,line):
return True
def help_exit(self):
print "退出命令,返回主循环"
def do_quit(self,line):#这个的do_exit和do_quit并没有什么区别
return True
def help_quit(self):
print "返回主循环"
class MyShell(Cmd):
def __init__(self):
Cmd.__init__(self)
self.prompt="Oxo>"
self.intro="""
这是个玩具,目的用于测试cmd
大家都退下吧
"""
self.doc_header="修改help帮助信息头的"
self.doc_leader='这里是leader'#其他两个misc_header undoc_header是无效的
def preloop(self):
print u"运行之前的欢迎信息"
def postloop(self):
print u"运行之后的结束信息"
#def precmd(self, line):这个钩子函数基本上是用不到,也许调试会用
# print "print this line before do a command"
# return Cmd.precmd(self, line)
# def postcmd(self, stop, line):#这个钩子函数基本用不到
# print "print this line after do a command"
# return Cmd.postcmd(self, stop, line)
def do_hello(self,line):
print u"你好"
print line
def help_hello(self):
print u"hello后面可接参数欢迎具体的某个人"
#options是自动补全的
def complete_hello(self,text,line,begidx,endidx):
if not text:#列出可选参数
completions=['timo','jack','jams']
return completions
else:
completions=['timo','jack','jams']#补全参数
return [i for i in completions if i.startswith(text)]
def do_test(self, line):
i=TestCmd()#嵌套新的解释器
i.prompt=self.prompt[:-1] +':Test>'
i.cmdloop()
def help_test(self):
print u"这就是一个测试"
def do_exit(self,line):
print u"我退出!!"
#sys.exit()不需要自己退出的,会有问题
return True
def help_exit(self):
print "退出交互器"
def emptyline(self):#输入命令为空处理办法
pass
def default(self,line):#输入无效命令处理办法
print u"没有这个命令"
MyShell().cmdloop()
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: craftsman2020
from __future__ import print_function
import sys
import cmd
from paramikotools import SSHConnection
VERSION = int(sys.version_info[0])
TRADERS = {'a': 'aaa', 'b': 'bbb'}
RUN_DICT = {}
SFTP_ACCOUNTS = {
'jack': '123456',
'aaa': '666666',
'bbb': '888888',
}
SERVERS = {
'server_123': ['101.122.122.122', 55555, 'jack', SFTP_ACCOUNTS['jack'], ['hahaha', 'wowowo'], []],
}
class ServerCmd(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self)
cmd.Cmd.intro = "### Please input the name of server, Example: server_123"
def default(self, server):
print('server = ', server)
if server in SERVERS:
print(SERVERS[server])
RUN_DICT['server'] = server
return True
else:
print(u'### 请检查server信息是否正确! server参数可配置的范围:\n{}'.format([i for i in SERVERS]))
return False
def preloop(self):
print("### Welcome to Server module")
def postloop(self):
print("### Exit Server module")
def do_q(self, line):
return True
def help_q(self):
print("### 返回主循环")
class TraderCmd(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self)
cmd.Cmd.intro = "### Please input the abbreviation of Trader's name, Example: a b"
def default(self, trader):
traders = trader.split()
print('traders = ', traders)
traders = [i.strip() for i in traders]
traders_dic = dict()
for t in traders:
if t in TRADERS:
traders_dic[t] = TRADERS[t]
else:
print(u'### 请检查trader信息是否正确! trader参数可配置的范围: \n{}'.format(TRADERS))
return False
print(traders_dic)
RUN_DICT['traders'] = traders_dic
return True
def preloop(self):
print("### Welcome to Trader module")
def postloop(self):
print("### Exit Trader module")
def do_q(self, line):
return True
def help_q(self):
print("### 返回主循环")
class OldAccountCmd(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self)
cmd.Cmd.intro = "### Please input the old account, Example: hahaha"
def default(self, old_account):
print('old_account = ', old_account)
if old_account in SERVERS[RUN_DICT['server']][-2]:
RUN_DICT['old_account'] = old_account
return True
else:
print(u'### 请检查old_account信息是否正确! old_account参数可配置的范围: \n{}'.format(SERVERS[RUN_DICT['server']][-2]))
return False
def preloop(self):
print("### Welcome to OldAccount module")
def postloop(self):
print("### Exit OldAccount module")
def do_q(self, line):
return True
def help_q(self):
print("### 返回主循环")
class NewAccountCmd(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self)
cmd.Cmd.intro = "### Please input new accounts:"
def default(self, new_account):
new_accounts = new_account.split()
print('new_accounts = ', new_accounts)
new_accounts = [i.strip() for i in new_accounts]
RUN_DICT['new_accounts'] = new_accounts
return True
def preloop(self):
print("### Welcome to NewAccount module")
def postloop(self):
print("### Exit NewAccount module")
def do_q(self, line): # 这个的do_exit和do_quit并没有什么区别
return True
def help_q(self):
print("### 返回主循环")
class MyShell(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self)
self.prompt = "main>>>"
self.intro = """### Start deploying >>> """
self.doc_header = "Commands"
self.doc_leader = 'this is leader' # 其他两个misc_header undoc_header是无效的
def do_help(self, line):
print('==============================================================')
print('module: { server, trader, old_account, new_account, run, exit}')
print('--------------------------------------------------------------')
print(u'server: 配置服务器参数, 只能输入SERVERS中的服务器名称')
print(u'trader: 配置trader参数, 只能输入TRADERS中的trader名称')
print(u'old_account: 模板账户, 只能输入SERVERS中的模板账户名称')
print(u'new_account: 新账户, 新上线的账户名称')
print(u'run: 根据配置的参数, 开始部署')
print(u'exit: 退出交互器')
print('==============================================================')
def preloop(self):
self.do_help('')
print('******************************************************')
print(u"1、进入各模块配置参数: server, trader, old, new")
print(u"2、核对参数无误后, run")
print('******************************************************')
def postloop(self):
print(u"程序运行结束!")
def do_server(self, line):
s = ServerCmd() # 嵌套新的解释器
s.prompt = self.prompt + ':Server>>>'
s.cmdloop()
def do_trader(self, line):
t = TraderCmd() # 嵌套新的解释器
t.prompt = self.prompt + ':Trader>>>'
t.cmdloop()
def help_server(self):
print(u"进入Server模块设置服务器配置项")
def help_trader(self):
print(u"进入Trader模块设置trader配置项")
def do_old(self, old_account):
o = OldAccountCmd() # 嵌套新的解释器
o.prompt = self.prompt + ':OldAccount>>>'
o.cmdloop()
def help_old(self):
print(u"进入OldAccount模块, 设置OldAccount配置项")
def do_new(self, new_account):
n = NewAccountCmd() # 嵌套新的解释器
n.prompt = self.prompt + ':NewAccount>>>'
n.cmdloop()
def help_new(self):
print(u"进入NewAccount模块, 设置NewAccount配置项")
def do_run(self, line):
print('RUN_DICT = ', RUN_DICT)
deploy()
def help_run(self):
print(u"参数配置完成后, 开始运行...")
# options是自动补全的 [python2 windows会自动补全]
def completedefault(self, text, line, begidx, endidx):
if not text: # 列出可选参数
completions = ['server', 'trader', 'old_account', 'new_account', 'run']
return completions
else:
completions = ['server', 'trader', 'old_account', 'new_account', 'run'] # 补全参数
return [i for i in completions if i.startswith(text)]
def do_exit(self, line):
print("Exit Program!")
# sys.exit()不需要自己退出的,会有问题
return True
def help_exit(self):
print(u"退出交互器")
def emptyline(self):
pass
def default(self, line):
print(u"没有这个命令")
def do_EOF(self, line):
return True
def deploy():
# python2
print("test hello world!")
MyShell().cmdloop()