演示代码可以在这里找到:https://github.com/neal1991/articles/blob/master/python-tab-auto-completion/autocompletion.py,接下来的讲解将以这份代码为例子。
什么是Tab自动补全和历史命令管理
在命令行中,我们经常需要输入很长的命令,会出现拼写错误、错误的命令、或者常见的命令不够智能的情况。Tab自动补全和历史命令管理正是这些问题的解决方案。
Tab自动补全: 在输入命令时可以利用Tab键,来自动补全命令。当输入的文字只有一个可能性,或者系统能够解决同名问题的时候,就能够自动匹配。如果有多个匹配,则可以通过多敲几个字母来缩小范围。
历史命令管理: 在输入命令时,我们经常需要输入之前输入过的某个命令。此时,如果可以通过上下箭头选择之前的命令,那么就可以省去不少的重复输入。
Python实现Tab自动补全和历史命令管理的方法
实现Tab自动补全和历史命令管理的方法便是通过输入的字符来快速查询匹配的命令传递给控制台。
通过读取控制台输入,来实现Tab自动补全
在Python中通过使用readline库,我们可以监控控制台的输入流。我们可以找到当前输入流中的最后一个字符,然后将标记位移到最后一个字符后,以使进行自动补全,如下所示:
line_buffer = readline.get_line_buffer()
line_buffer += " "
if re.search(r"^\s*ls\s*$", line_buffer):
line_buffer = "ls --color=auto"
line_buffer = re.sub("\\\s", " ", line_buffer)
start_index = readline.get_begidx()
end_index = readline.get_endidx()
word_part = line_buffer[start_index:end_index]
match_list = [item for item in self._match_list if item.startswith(word_part)]
在上面的代码中,我们首先使用readline.get_line_buffer()
读取当前控制台输入的内容,在行尾加上一个空格,然后把正则表达式作用在当前输入字符的内容上。如果匹配到的是ls
命令,我们加上--color=auto
参数,即着色显示文件目录。如果你习惯使用ls
显示目录,这段代码加上这个判断非常方便。在处理好输入字符后,我们读取了当前输入字符的起始位置和结束位置,以确定我们需要自动补全的字符。在此之后,我们就可以对历史命令进行查找,如上代码所示,以便找到所有匹配的命令,这些命令也是我们需要展示在控制台供用户选择的命令。
readline.parse_and_bind("tab: complete")
readline.set_completer_delims(" \t\n()\"\'")
readline.set_completer(self.match)
在这段代码中,我们首先为Tab键绑定了自动完成操作。接下来我们为自动完成操作设置了分隔符,如下所示:
readline.set_completer_delims(" \t\n()\"\'")
在上面的代码中,我们设置了Tab、空格、换行、括号以及引号都是输入的分隔符。
接下来,我们将一个函数作为自动完成函数传递给readline.set_completer
方法。在这个函数中,我们根据当前输入的东西和历史匹配的命令过滤出要展示在控制台上供用户选择的命令。由于使用Tab自动完成的目的是找到历史命令。因此我们方法的内容需要看下面的历史命令管理部分。
通过读取控制台输入来实现历史命令管理
在Python中,我们的历史命令管理主要通过readline模块实现。
为了使用历史命令管理,我们可以使用readline库中的readline
方法获取当前行的内容,以便在用户按上下箭头时,将当前行中的内容载入下一个或上一个命令。接下来,我们可以读取历史命令列表,从而遍历在用户在控制台中输入过的历史记录。最常见的历史管理方法有两种:
第一种方法是使用readline模块中的readline.get_history_length()
方法来获取历史记录列表的长度,之后调用readline.get_history_item(index)
方法来读取我们需要的记录,并返回一个字符串。字符串最后附有一个代表每个选项的索引,如下所示:
index = readline.get_current_history_length() - 1
state = readline.get_history_item(index + 1)
print('%s - %s' % (index, state))
在上面的代码中,我们读取历史记录列表的长度以及读取了历史记录列表中的第一个匹配项。注意到,我们的索引从0开始,但readline.get_current_history_length()
返回的数据却是从1开始计算的,所以我们需要使用index + 1
来读取正确的偏移量。
第二种方法是使用readline模块中的readline.get_history_item(-n)
方法来获取历史记录列表中的最后n项,值为负数。当值为-1时,我们取到的是最后一项。这是因为负数表示取本身以及向前的项数,而不是从前向后的项数。
for index in range(max(self._history_list, None, item for item in 0, length):
line_buffer += self._history_list[index]
在这段代码中,我们首先定义了一个使用for
循环从0到历史记录列表长度的循环,以便读取历史记录列表的所有项,并将其保存在当前命令的单元中。
总结
自动补全能够快速让用户在控制台中找到他们想要的命令,因此是命令行工具开发中不可缺少的一部分。通过使用readline库,Python实现了自动匹配并显示历史命令,并为使用者提供了极大的方便。此外,上述的代码实现,也可以应用到其他的开发领域中,如网站开发、Python编程、以及命令从新编写等上。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python实现Tab自动补全和历史命令管理的方法 - Python技术站