如何编写bash自动补全脚本(3)

命令来显示执行历史中的最近50条命令以及它们的序号。这里我们唯一需要处理的是将原始命令输出的制表符替换成空格,以便于更好的展示。这个工作由sed来完成。

将自动补全脚本做如下改动:

#/usr/bin/env bash _dothis_completions() { COMPREPLY=($(compgen -W "$(fc -l -50 | sed 's/\t//')" -- "${COMP_WORDS[1]}")) } complete -F _dothis_completions dothis

在控制台中source该脚本并验证:

$ dothis <tab><tab> 632 source dothis-completion.bash 649 source dothis-completion.bash 666 cat ~/.bash_profile 633 clear 650 clear 667 cat ~/.bashrc 634 source dothis-completion.bash 651 source dothis-completion.bash 668 clear 635 source dothis-completion.bash 652 source dothis-completion.bash 669 install ./dothis ~/bin/dothis 636 clear 653 source dothis-completion.bash 670 dothis 637 source dothis-completion.bash 654 clear 671 dothis 6546545646 638 clear 655 dothis 654 672 clear 639 source dothis-completion.bash 656 dothis 631 673 dothis 640 source dothis-completion.bash 657 dothis 150 674 dothis 651 641 source dothis-completion.bash 658 dothis 675 source dothis-completion.bash 642 clear 659 clear 676 dothis 651 643 dothis 623 ls -la 660 dothis 677 dothis 659 644 clear 661 install ./dothis ~/bin/dothis 678 clear 645 source dothis-completion.bash 662 dothis 679 dothis 665 646 clear 663 install ./dothis ~/bin/dothis 680 clear 647 source dothis-completion.bash 664 dothis 681 clear 648 clear 665 cat ~/.bashrc

效果不错。但是还存在一个问题,当我们输入一个数字之后再按tab键,会出现:

$ dothis 623<tab> $ dothis 623 ls 623 ls -la ... $ dothis 623 ls 623 ls 623 ls 623 ls 623 ls -la

出现这个问题是因为在自动补全脚本中,我们使用了${COMP_WORDS[1]}来获取dothis命令之后的第一个词(在上述代码片段中为623)。因此当tab键按下时,相同的自动补全列表会一再出现。

要修复这个问题,我们将在已经输入了至少一个参数之后,不再允许继续进行自动补全。因此需要在函数中增加对COMP_WORDS数组大小的前置判断:

#/usr/bin/env bash _dothis_completions() { if [ "${#COMP_WORDS[@]}" != "2" ]; then return fi COMPREPLY=($(compgen -W "$(fc -l -50 | sed 's/\t//')" -- "${COMP_WORDS[1]}")) } complete -F _dothis_completions dothis

source脚本并重试:

$ dothis 623<tab> $ dothis 623 ls -la<tab> # 成功:此时没有触发自动补全

当前脚本还有一个不尽如人意的地方。我们希望展示历史记录序号给用户的同时展示对应的命令,以帮助用户决定选择哪个历史命令。但是当补全建议中有且只有一个时候,应该能够通过自动补全机制自动选择,而不要追加命令文本

因为dothis命令实际只接受一个表示执行历史序号的参数,并且没有对多余参数进行校验。当我们的自动补全函数计算出只有一个结果时,应该去除序号后面的命令文本,只返回命令序号。

为了实现这个功能,我们需要将compgen命令的返回值保存到数组变量中,并且检查当其大小,当大小为1时,去除这个唯一的值数字后面跟随的文本;否则直接返回这个数组。

将自动补全脚本修改成:

#/usr/bin/env bash _dothis_completions() { if [ "${#COMP_WORDS[@]}" != "2" ]; then return fi # keep the suggestions in a local variable local suggestions=($(compgen -W "$(fc -l -50 | sed 's/\t/ /')" -- "${COMP_WORDS[1]}")) if [ "${#suggestions[@]}" == "1" ]; then # if there's only one match, we remove the command literal # to proceed with the automatic completion of the number local number=$(echo ${suggestions[0]/%\ */}) COMPREPLY=("$number") else # more than one suggestions resolved, # respond with the suggestions intact COMPREPLY=("${suggestions[@]}") fi } complete -F _dothis_completions dothis 注册自动补全脚本

如果我们希望将自动补全脚本应用到个人账户,可以在.bashrc文件中source这个脚本:

source <path-to-your-script>/dothis-completion.bash

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/7abde8daf5e5ef373eea3856d785025d.html