使用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中文件遍历的两种方法
Jun 16 Python
python读取TXT到数组及列表去重后按原来顺序排序的方法
Jun 26 Python
基于python yield机制的异步操作同步化编程模型
Mar 18 Python
使用Nginx+uWsgi实现Python的Django框架站点动静分离
Mar 21 Python
django 修改server端口号的方法
May 14 Python
Django 根据数据模型models创建数据表的实例
May 27 Python
python学生信息管理系统(初级版)
Oct 17 Python
python使用ddt过程中遇到的问题及解决方案【推荐】
Oct 29 Python
Python使用__new__()方法为对象分配内存及返回对象的引用示例
Sep 20 Python
在django-xadmin中APScheduler的启动初始化实例
Nov 15 Python
Python大数据之使用lxml库解析html网页文件示例
Nov 16 Python
Python pandas RFM模型应用实例详解
Nov 20 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
ExtJS与PHP、MySQL实现存储的方法
2010/04/02 PHP
php时间戳转换的示例
2014/03/31 PHP
通过PHP自带的服务器来查看正则匹配结果的方法
2015/12/24 PHP
示例详解Laravel重置密码代码重构
2016/08/10 PHP
php微信公众号开发模式详解
2016/11/28 PHP
PHP使用pdo连接access数据库并循环显示数据操作示例
2018/06/05 PHP
HTTP头隐藏PHP版本号实现过程解析
2020/12/09 PHP
又一个图片自动缩小的JS代码
2007/03/10 Javascript
仿微博字符限制效果实现代码
2012/04/20 Javascript
让元素在网页中可拖动示例代码
2013/08/13 Javascript
element-ui 限制日期选择的方法(datepicker)
2018/05/16 Javascript
js原生map实现的方法总结
2020/01/19 Javascript
Vue 自适应高度表格的实现方法
2020/05/13 Javascript
Node.js API详解之 net模块实例分析
2020/05/18 Javascript
js实现自定义右键菜单
2020/05/18 Javascript
[02:39]DOTA2英雄基础教程 天怒法师
2013/11/29 DOTA
多线程爬虫批量下载pcgame图片url 保存为xml的实现代码
2013/01/17 Python
python编写网页爬虫脚本并实现APScheduler调度
2014/07/28 Python
Python的Django框架中的数据库配置指南
2015/07/17 Python
python 回调函数和回调方法的实现分析
2016/03/23 Python
python字典快速保存于读取的方法
2018/03/23 Python
Python类装饰器实现方法详解
2018/12/21 Python
对python中UDP,socket的使用详解
2019/08/22 Python
使用Python的networkx绘制精美网络图教程
2019/11/21 Python
python实现人机猜拳小游戏
2020/02/03 Python
通过python调用adb命令对App进行性能测试方式
2020/04/23 Python
详细分析Python collections工具库
2020/07/16 Python
精灵市场:Pixie Market
2019/06/18 全球购物
C#笔试题和英文面试题
2013/02/07 面试题
生物技术研究生自荐信
2013/11/12 职场文书
2014年办公室个人工作总结
2014/11/12 职场文书
优秀共青团员事迹材料
2014/12/25 职场文书
某某幼儿园的教育教学管理调研分析报告
2019/11/29 职场文书
MySQL 存储过程的优缺点分析
2021/05/20 MySQL
深入理解Pytorch微调torchvision模型
2021/11/11 Python
Go 中的空白标识符下划线
2022/03/25 Golang