Python之cmd模块

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. 其他说明

  1. 当输入空行的时候,我们可以重载emptyline()来处理:
def emptyline(self):
    print 'please input command!'

在这里插入图片描述

  1. 自定义我们自己的交互式提示字符串
prompt = 'pyFun>'

在这里插入图片描述

  1. 自定义我们的欢迎语:
intro = 'Welcom to pyFun!'

在这里插入图片描述

  1. 使程序能够正常接收ctrl+c的退出方式
try:
    os.system('cls')
    client = Client()
    client.cmdloop()
except:
    exit()

在我按下ctrl+c之后能够正常退出不报错
在这里插入图片描述

  1. 当输入无法识别的命令时,使用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()

5. 综合案例2

#!/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()


加星
点关注
谢谢
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值