使用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登陆asp网站页面的实现代码
Jan 14 Python
Linux系统上Nginx+Python的web.py与Django框架环境
Dec 25 Python
python实现下载整个ftp目录的方法
Jan 17 Python
numpy中索引和切片详解
Dec 15 Python
Python实现识别手写数字 Python图片读入与处理
Mar 23 Python
python自制包并用pip免提交到pypi仅安装到本机【推荐】
Jun 03 Python
Django用户认证系统 组与权限解析
Aug 02 Python
pygame实现俄罗斯方块游戏(基础篇1)
Oct 29 Python
tensorflow查看ckpt各节点名称实例
Jan 21 Python
在python3中实现更新界面
Feb 21 Python
python 数据类型强制转换的总结
Jan 25 Python
利用Python实现模拟登录知乎
May 25 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
2.PHP入门
2006/10/09 PHP
基于PHP实现假装商品限时抢购繁忙的效果
2015/10/16 PHP
Thinkphp3.2简单解决多文件上传只上传一张的问题
2017/09/26 PHP
thinkPHP框架中执行事务的方法示例
2018/05/31 PHP
基于jquery的监控数据是否发生改变
2011/04/11 Javascript
jquery load事件(callback/data)使用方法及注意事项
2013/02/06 Javascript
js/jquery判断浏览器类型的方法小结
2015/05/12 Javascript
基于JavaScript实现移动端TAB触屏切换效果
2015/10/20 Javascript
jquery验证邮箱格式并显示提交按钮
2015/11/07 Javascript
js跨域请求数据的3种常用的方法
2015/12/01 Javascript
JavaScript中使用import 和require打包后实现原理分析
2018/03/07 Javascript
浅谈Vue-cli单文件组件引入less,sass,css样式的不同方法
2018/03/13 Javascript
nodejs搭建本地服务器轻松解决跨域问题
2018/03/21 NodeJs
vue.js编译时给生成的文件增加版本号
2018/09/17 Javascript
clipboard在vue中的使用的方法示例
2018/10/19 Javascript
vue学习笔记之过滤器的基本使用方法实例分析
2020/02/01 Javascript
python学习之面向对象【入门初级篇】
2017/01/21 Python
python将txt文档每行内容循环插入数据库的方法
2018/12/28 Python
python wxpython 实现界面跳转功能
2019/12/17 Python
python利用Excel读取和存储测试数据完成接口自动化教程
2020/04/30 Python
Python Matplotlib绘图基础知识代码解析
2020/08/31 Python
CSS3模块的目前的状况分析
2010/02/24 HTML / CSS
利用html5 canvas动态画饼状图的示例代码
2018/04/02 HTML / CSS
HTML5组件Canvas实现图像灰度化(步骤+实例效果)
2013/04/22 HTML / CSS
大学生求职简历的自我评价
2013/10/21 职场文书
我未来的职业规划范文
2014/01/11 职场文书
宇宙与人观后感
2015/06/05 职场文书
银行大堂经理培训心得体会
2016/01/09 职场文书
大学军训心得体会800字
2016/01/11 职场文书
导游词之镇江西津古渡
2019/11/06 职场文书
八年级作文之我的母亲
2019/12/10 职场文书
pygame面向对象的飞行小鸟实现(Flappy bird)
2021/04/01 Python
go:垃圾回收GC触发条件详解
2021/04/24 Golang
Python中OpenCV实现查找轮廓的实例
2021/06/08 Python
Pandas 稀疏数据结构的实现
2021/07/25 Python
JavaScript中10个Reduce常用场景技巧
2022/06/21 Javascript