使用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调用C语言开发的共享库方法实例
Mar 18 Python
Django如何实现内容缓存示例详解
Sep 24 Python
Flask web开发处理POST请求实现(登录案例)
Jul 26 Python
djang常用查询SQL语句的使用代码
Feb 15 Python
python实现kmp算法的实例代码
Apr 03 Python
pycharm创建scrapy项目教程及遇到的坑解析
Aug 15 Python
Python pandas自定义函数的使用方法示例
Nov 20 Python
详解anaconda离线安装pytorchGPU版
Sep 08 Python
python3定位并识别图片验证码实现自动登录功能
Jan 29 Python
Python运算符+与+=的方法实例
Feb 18 Python
pandas 按日期范围筛选数据的实现
Feb 20 Python
Python爬虫中urllib3与urllib的区别是什么
Jul 21 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
从网上搜到的phpwind 0day的代码
2006/12/07 PHP
php 备份数据库代码(生成word,excel,json,xml,sql)
2013/06/23 PHP
PHP7.0版本备注
2015/07/23 PHP
PHP 设计模式系列之 specification规格模式
2016/01/10 PHP
PHP等比例压缩图片的实例代码
2018/07/26 PHP
PHP getDocNamespaces()函数讲解
2019/02/03 PHP
js实现图片放大缩小功能后进行复杂排序的方法
2012/11/08 Javascript
关于extjs treepanel复选框选中父节点与子节点的问题
2013/04/02 Javascript
Query中click(),bind(),live(),delegate()的区别
2013/11/19 Javascript
jquery datepicker参数介绍和示例
2014/04/15 Javascript
JavaScript中获取Radio被选中的值
2015/11/11 Javascript
bootstrap-treeview自定义双击事件实现方法
2016/01/09 Javascript
js点击返回跳转到指定页面实现过程
2020/08/20 Javascript
JavaScript导航脚本判断当前导航
2016/07/12 Javascript
深入理解JS中的Function.prototype.bind()方法
2016/10/11 Javascript
JS把字符串格式的时间转换成几秒前、几分钟前、几小时前、几天前等格式
2019/07/10 Javascript
JavaScript实现横版菜单栏
2020/03/17 Javascript
koa中间件核心(koa-compose)源码解读分析
2020/06/15 Javascript
JavaScript实现动态生成表格
2020/08/02 Javascript
Vue实现计算器计算效果
2020/08/17 Javascript
Tornado服务器中绑定域名、虚拟主机的方法
2014/08/22 Python
python分割文件的常用方法
2014/11/01 Python
Python数据结构之栈、队列及二叉树定义与用法浅析
2018/12/27 Python
Django实现文件上传和下载功能
2019/10/06 Python
对python pandas中 inplace 参数的理解
2020/06/27 Python
Pytho爬虫中Requests设置请求头Headers的方法
2020/09/22 Python
Python 转移文件至云对象存储的方法
2021/02/07 Python
CSS3文本换行word-wrap解决英文文本超过固定宽度不换行
2013/10/10 HTML / CSS
Html5定位终极解决方案
2020/02/05 HTML / CSS
Under Armour美国官网:美国知名高端功能性运动品牌
2016/09/05 全球购物
程序运行正确, 但退出时却"core dump"了,怎么回事
2014/02/19 面试题
怎样写观后感
2015/06/19 职场文书
2016道德模范先进事迹材料
2016/02/26 职场文书
Nginx源码编译安装过程记录
2021/11/17 Servers
Java实现带图形界面的聊天程序
2022/06/10 Java/Android
win10系统计算机图标怎么调出来?win10调出计算机图标的方法
2022/08/14 数码科技