1. 在很多情况,在编写的终端程序中会有命令交互部分
tools >show plugins<TAB> plugins/portscan plugins/webinfo tools >
希望能出现如上效果
2. python 在这方面给与了一定的处理方式
if 'linux' in sys.platform: import readline elif 'darwin' in sys.platform: sys.path.insert(0, 'module/readline_osx') import readline elif 'win32' == sys.platform or 'win64' == sys.platform: sys.path.insert(0, 'module/readline_windows') import readline其中 readline 模块可提供TAB补全功能
url:https://docs.python.org/2/library/readline.html#example
3. 在实际使用中官方给与的例子如下
import os import readline histfile = os.path.join(os.path.expanduser("~"), ".pyhist") try: readline.read_history_file(histfile) # default history len is -1 (infinite), which may grow unruly readline.set_history_length(1000) except IOError: pass import atexit atexit.register(readline.write_history_file, histfile) del os, histfile The following example extends the :class:`code.InteractiveConsole` class to support history save/restore. :: import code import readline import atexit import os class HistoryConsole(code.InteractiveConsole): def __init__(self, locals=None, filename="", histfile=os.path.expanduser("~/.console-history")): code.InteractiveConsole.__init__(self, locals, filename) self.init_history(histfile) def init_history(self, histfile): readline.parse_and_bind("tab: complete") if hasattr(readline, "read_history_file"): try: readline.read_history_file(histfile) except IOError: pass atexit.register(self.save_history, histfile) def save_history(self, histfile): readline.set_history_length(1000) readline.write_history_file(histfile)
其中存在一个问题就是无法将带有空格的命令补全出来
4. 经过研究发现通过如下代码是可以实现
通过读取代码发现可以通过 complete_XXXXX 通过这种格式对特定命令进行自定义补全 如:complete_extra 输入 extra进行补全的时候会调用complete_extra函数,
import os import re import readline COMMANDS = ['extra', 'extension', 'stuff', 'errors', 'email', 'foobar', 'foo'] RE_SPACE = re.compile('.*\s+$', re.M) class Completer(object): def _listdir(self, root): "List directory 'root' appending the path separator to subdirs." res = [] for name in os.listdir(root): path = os.path.join(root, name) if os.path.isdir(path): name += os.sep res.append(name) return res def _complete_path(self, path=None): "Perform completion of filesystem path." if not path: return self._listdir('.') dirname, rest = os.path.split(path) tmp = dirname if dirname else '.' res = [os.path.join(dirname, p) for p in self._listdir(tmp) if p.startswith(rest)] # more than one match, or single match which does not exist (typo) if len(res) > 1 or not os.path.exists(path): return res # resolved to a single directory, so return list of files below it if os.path.isdir(path): return [os.path.join(path, p) for p in self._listdir(path)] # exact file match terminates this completion return [path + ' '] def complete_extra(self, args): "Completions for the 'extra' command." if not args: return self._complete_path('.') # treat the last arg as a path and complete it return self._complete_path(args[-1]) def complete(self, text, state): "Generic readline completion entry point." buffer = readline.get_line_buffer() line = readline.get_line_buffer().split() # show all commands if not line: return [c + ' ' for c in COMMANDS][state] # account for last argument ending in a space if RE_SPACE.match(buffer): line.append('') # resolve command to the implementation function cmd = line[0].strip() if cmd in COMMANDS: impl = getattr(self, 'complete_%s' % cmd) args = line[1:] if args: return (impl(args) + [None])[state] return [cmd + ' '][state] results = [c + ' ' for c in COMMANDS if c.startswith(cmd)] + [None] return results[state] comp = Completer() # we want to treat '/' as part of a word, so override the delimiters readline.set_completer_delims(' \t\n;') readline.parse_and_bind("tab: complete") readline.set_completer(comp.complete) raw_input('Enter section name: ')
5. 通过上述方法实现了自定义TAB补全
但是可能会遇到更多其他需求比如想要获取终端想要补全的全部命令信息
def complete(self, text, state): """ :param text: :param state: :return: """ buff = readline.get_line_buffer() line = readline.get_line_buffer().split()
可以在类里重写如上函数获取TAB需要补全的全部命令信息
>python complete.py Enter section name > extextension extra Enter section name > extra foofoo.py foo.txt foo/ Enter section name > extra foo/foo/bar.txt foo/baz.txt Enter section name > extra foo/bar.txt
参考链接:
https://stackoverflow.com/questions/5637124/tab-completion-in-pythons-raw-input
https://segmentfault.com/q/1010000006090261