使用python模拟命令行终端的示例


Posted in Python onAugust 13, 2019

可以对?显示帮助信息,需要立即获取输入的字符,因此需要用到termios模块

另外需要对tab键做处理,当按下tab键时可以进行自动补全

#! /usr/bin/env python
# coding=utf-8
 
import os
import sys
import tty
import termios
 
'''
Enter: 13
Back:  127
?:   63
C-h:  8
C-w:  23
Tab:  9
C-u:  21
C-c:  3
C-d:  4
C-\:  28
SPACE: 32
'''
 
CLI_KEY_CNCR = 13
CLI_KEY_BACK = 127
CLI_KEY_QMARK = 63
CLI_KEY_CTRLH = 8
CLI_KEY_CTRLW = 23
CLI_KEY_TAB  = 9
CLI_KEY_CTRLU = 21
CLI_KEY_CTRLC = 3
CLI_KEY_CTRLD = 4
CLI_KEY_QUIT = 28
CLI_KEY_SPACE = 32
CLI_KEY_TABLEN = 4
 
class CLI(object):
  def __init__(self):
    self.line = ''
    self.line_complete = ''
    self.completer_on = False
    self.completer_dict = {}
    self.completer_dict_keys = self.completer_dict.keys()
    self.completer_id = 0
    self.completer_cnt = len(self.completer_dict)
  def getch(self):
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
      tty.setraw(fd)
      ch = sys.stdin.read(1)
    finally:
      termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return ch
  def completer_kw_update(self):
    self.completer_dict_keys = self.completer_dict.keys()
    self.completer_dict_keys.sort()
    self.completer_cnt = len(self.completer_dict)
  def completer_kw_add(self, key, word):
    self.completer_dict[key] = word
    self.completer_kw_update()
  def completer_kw_clear(self):
    self.completer_dict.clear()
    self.completer_id_update()
  def completer_id_update(self):
    self.completer_kw_update()
    if self.completer_id < self.completer_cnt - 1:
      self.completer_id += 1
    else:
      self.completer_id = 0
  def completer_wd_select(self, word):
    if not word:
      return ''
    cnt = self.completer_cnt
    while cnt>0:
      completer = self.completer_dict_keys[self.completer_id]
      self.completer_id_update()
      cnt -= 1
      if word == completer[:len(word)]:
        return completer[len(word):]
    return ''
  def printf(self, info=''):
    sys.stdout.write(info)
  def show_spec_len_str(self, info, maxlen, spacech=' '):
    'display a string of the specified length'
    maxlen = maxlen
    infolen = len(info)
    if maxlen < infolen:
      maxlen = infolen
    while infolen>0:
      ch = info[-infolen]
      for i in range(self.char_memory_len(ch)):
        self.printf(info[i-infolen])
      infolen -= self.char_memory_len(ch)
      maxlen -= self.char_display_len(ch)
    while maxlen>0:
      self.printf(spacech)
      maxlen -= self.char_display_len(spacech)
  def show_help_info(self):
    if self.completer_on:
      line = self.line_complete
    else:
      line = self.line
    lastwd = ''
    show_all = False
    if not line or line[-1] == ' ':
      show_all = True
    else:
      lastwd = line.split()[-1]
    if self.completer_dict:
      maxlen = max([len(info) for info in self.completer_dict])
    else:
      maxlen = 12
    for info in self.completer_dict:
      if show_all or lastwd == info[:len(lastwd)]:
        self.printf(' ')
        self.show_spec_len_str(info, maxlen)
        self.printf(' ')
        self.printf(self.completer_dict[info])
        self.printf('\r\n')
  def is_chinese_char(self, ch):
    return ord(ch) > 127
  def char_display_len(self, ch):
    if self.is_chinese_char(ch):
      return 2
    elif ord(ch) == CLI_KEY_TAB:
      return CLI_KEY_TABLEN
    else:
      return 1
  def char_memory_len(self, ch):
    if self.is_chinese_char(ch):
      return 3
    else:
      return 1
  def rm_last_char(self, line):
    lastch = ''
    rmlen = 0
    if len(line)>0:
      lastch = line[-1]
      self.printf('\b \b' * self.char_display_len(lastch))
      rmlen = self.char_memory_len(lastch)
      if len(line) >= rmlen:
        line = line[:-(rmlen)]
      else:
        rmlen = len(line)
        line = ''
    return rmlen, line
  def rm_last_word(self, line):
    lastwd = ''
    linelen = len(line)
    rspacelen = linelen - len(line.rstrip())
    if not linelen:
      return line
    lastwd = line.split()[-1]
    backlen = len(lastwd) + rspacelen
    rmlen = 0
    while backlen>0 and line:
      rmlen, line = self.rm_last_char(line)
      backlen -= rmlen
    return line
  def rm_one_line(self, line):
    rmlen = 0
    while line:
      rmlen, line = self.rm_last_char(line)
    return line
  def do_line_complete_proc(self):
    line = self.line
    line_complete = self.line_complete
    lastwd = ''
    self.printf('\r\n')
    if self.line_complete:
      self.printf(self.line_complete)
    else:
      self.printf(self.line)
    if not line:
      return line
    lastwd = line.split()[-1]
    completer = self.completer_wd_select(lastwd)
    if not completer.strip():
      self.line_complete = line
      return line
    backlen = len(line_complete) - len(line)
    while backlen>0 and line_complete:
      rmlen, line_complete = self.rm_last_char(line_complete)
      backlen -= rmlen
    self.printf(completer)
    line_complete = line + completer
    self.line_complete = line_complete
  def do_line_complete_end(self):
    if self.completer_on:
      self.line = self.line_complete
      self.line_complete = ''
      self.completer_on = False
  def get_line(self):
    self.line = ''
    self.line_complete = ''
    self.completer_on = False
    while True:
      ch = self.getch()
      if ch == '\r' or ch == '\n':
        self.do_line_complete_end()
        self.printf('\r\n')
        break
      elif ord(ch) == CLI_KEY_BACK or ord(ch) == CLI_KEY_CTRLH:
        if self.completer_on:
          rmlen, self.line_complete = self.rm_last_char(self.line_complete)
        else:
          rmlen, self.line = self.rm_last_char(self.line)
        self.do_line_complete_end()
      elif ord(ch) == CLI_KEY_QMARK:
        self.printf('?')
        self.printf('\r\n')
        self.show_help_info()
        if self.completer_on:
          self.printf(self.line_complete)
        else:
          self.printf(self.line)
      elif ord(ch) == CLI_KEY_CTRLW:
        if self.completer_on:
          self.line_complete = self.rm_last_word(self.line_complete)
        else:
          self.line = self.rm_last_word(self.line)
        self.do_line_complete_end()
      elif ord(ch) == CLI_KEY_TAB:
        self.completer_on = True
        self.do_line_complete_proc()
      elif ord(ch) == CLI_KEY_CTRLD:
        if self.line:
          return self.line
        else:
          return ch
      elif ord(ch) == CLI_KEY_QUIT:
        self.printf('\r\n Interrupted by <Ctrl-\>.\r\n')
        sys.exit()
      elif ord(ch) == CLI_KEY_CTRLU:
        if self.completer_on:
          self.line_complete = self.rm_one_line(self.line_complete)
        else:
          self.line = self.rm_one_line(self.line)
        self.do_line_complete_end()
      elif ord(ch) == CLI_KEY_SPACE:
        self.printf(ch)
        if self.completer_on:
          self.line_complete += ch
        else:
          self.line += ch
      else:
        self.printf(ch)
        self.do_line_complete_end()
        self.line += ch
        # chinese qmask proc
        if ord(ch) == 159 and len(self.line)>= 3 and self.line[-3:] == '\xef\xbc\x9f':
          self.printf('\r\n')
          self.line = self.line[:-3]
          self.show_help_info()
          self.printf(self.line)
    return self.line
  def get_raw_line(self):
    self.raw_line = ''
    while True:
      ch = self.getch()
      if ch == '\r' or ch == '\n':
        self.printf('\r\n')
        break
      elif ord(ch) == CLI_KEY_BACK or ord(ch) == CLI_KEY_CTRLH:
        rmlen, self.raw_line = self.rm_last_char(self.raw_line)
      elif ord(ch) == CLI_KEY_CTRLW:
        self.raw_line = self.rm_last_word(self.raw_line)
      elif ord(ch) == CLI_KEY_TAB:
        self.printf(' ' * self.char_display_len(ch))
        self.raw_line += ch
      elif ord(ch) == CLI_KEY_CTRLD:
        if self.raw_line:
          return self.raw_line
        else:
          return ch
      elif ord(ch) == CLI_KEY_QUIT:
        self.printf('\r\n Interrupted by <Ctrl-\>.\r\n')
        sys.exit()
      elif ord(ch) == CLI_KEY_CTRLU:
        self.raw_line = self.rm_one_line(self.raw_line)
      else:
        self.raw_line += ch
        self.printf(ch)
    return self.raw_line
 
def test():
  cli = CLI()
  help_info = {
  	'hello0':   'say hello 0',
  	'hello1':   'say hello 1',
  	'hellohello': 'say hello hello',
  	'hellohehe': 'say hello hehe',
  	'hellohi':  'say hello hi',
  	'你好啊':   'say 你好啊',
  	'你好吗':   'say 你好吗',
  	'你好哈':   'say 你好哈',
  	}
  for key in help_info:
    cli.completer_kw_add(key, help_info[key])
  while True:
    line = cli.get_line()
    if len(line) == 1 and ord(line[0]) == CLI_KEY_CTRLD:
      break
    if line == 'quit':
      break
    print(line)
 
if __name__ == "__main__": 
  test()

以上这篇使用python模拟命令行终端的示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python 示例分享---逻辑推理编程解决八皇后
Jul 20 Python
Python中的一些陷阱与技巧小结
Jul 10 Python
使用Python的urllib和urllib2模块制作爬虫的实例教程
Jan 20 Python
Python实现简单过滤文本段的方法
May 24 Python
python操作MySQL 模拟简单银行转账操作
Sep 27 Python
python使用xslt提取网页数据的方法
Feb 23 Python
python实现对输入的密文加密
Mar 20 Python
Django 实现外键去除自动添加的后缀‘_id’
Nov 15 Python
TensorFlow基本的常量、变量和运算操作详解
Feb 03 Python
基于python爬取链家二手房信息代码示例
Oct 21 Python
python解压zip包中文乱码解决方法
Nov 27 Python
Python Http请求json解析库用法解析
Nov 28 Python
在macOS上搭建python环境的实现方法
Aug 13 #Python
解决Mac下使用python的坑
Aug 13 #Python
python 接口实现 供第三方调用的例子
Aug 13 #Python
python 爬取学信网登录页面的例子
Aug 13 #Python
利用anaconda作为python的依赖库管理方法
Aug 13 #Python
基于Python的图像数据增强Data Augmentation解析
Aug 13 #Python
python通过txt文件批量安装依赖包的实现步骤
Aug 13 #Python
You might like
php5 pdo新改动加载注意事项
2008/09/11 PHP
PHPMailer邮件发送的实现代码
2013/05/04 PHP
关于更改Zend Studio/Eclipse代码风格主题的介绍
2013/06/23 PHP
php导出word格式数据的代码实例
2013/11/25 PHP
php获取当前时间的毫秒数的方法
2014/01/26 PHP
PHP简单数据库操作类实例【支持增删改查及链式操作】
2016/10/10 PHP
在html页面中包含共享页面的方法
2008/10/24 Javascript
PNG背景在不同浏览器下的应用
2009/06/22 Javascript
js 小数取整的函数
2010/05/10 Javascript
juqery 学习之四 筛选查找
2010/11/30 Javascript
javascript+xml实现简单图片轮换(只支持IE)
2012/12/23 Javascript
js中substring和substr的详细介绍与用法
2013/08/29 Javascript
查找页面中所有类为test的结点的方法
2014/03/28 Javascript
浅谈javascript回调函数
2014/12/07 Javascript
JavaScript采用递归算法计算阶乘实例
2015/08/04 Javascript
简单学习JavaScript中的for语句循环结构
2015/11/10 Javascript
Select2.js下拉框使用小结
2016/10/24 Javascript
AngularJS 防止页面闪烁的方法
2017/03/09 Javascript
JS实现AES加密并与PHP互通的方法分析
2017/04/19 Javascript
Node.js 使用流实现读写同步边读边写功能
2017/09/11 Javascript
jQuery实现的简单动态添加、删除表格功能示例
2017/09/21 jQuery
vue-cli的eslint相关用法
2017/09/29 Javascript
vue获取data数据改变前后的值方法
2019/11/07 Javascript
[47:43]完美世界DOTA2联赛PWL S3 Magama vs GXR 第二场 12.19
2020/12/24 DOTA
利用python代码写的12306订票代码
2015/12/20 Python
keras.layer.input()用法说明
2020/06/16 Python
python读取xml文件方法解析
2020/08/04 Python
俄罗斯GamePark游戏商店网站:购买游戏、游戏机和配件
2020/03/13 全球购物
华为的Java面试题
2014/03/07 面试题
应届大学生简历中的自我评价
2014/01/15 职场文书
《跨越海峡的生命桥》教学反思
2014/02/24 职场文书
幼儿教师师德师风演讲稿
2014/08/22 职场文书
党支部对照检查材料
2014/08/25 职场文书
反腐倡廉警示教育活动心得体会
2014/09/04 职场文书
2014年大学宣传部工作总结
2014/12/19 职场文书
一篇文章带你了解Python和Java的正则表达式对比
2021/09/15 Python