在下所在的公司定义了一种路径,配合自定义的 loader 命令;遂命令在下完成自定义路径的自动补全需求。

关于Linux Shell命令自动补全已有的一些优秀 blog

本人遇到的一些需求及解决方案:

需求一:从多个路径下获取补全候选项,并做去重
  • 解决方案写一个循环获取所有候选项,并且去重。这里记录一下 shell数组去重 ,和数组的使用。
array=()
array[0]="hello"
array[1]="hello"
# 数组去重(从一个贴吧里找到的,非原创)
array=($(awk -vRS=' ' '!a[$1]++' <<< ${array[@]}))

# 数组的使用(同样非原创,找不到链接了)
COMPREPLY=($(compgen -W "${array[*]}" -- "he"))
需求二:自定义路径 转化成 系统路径
  • 比如:我需要把 test:hello.world 转成 /.../hello/world
  • 这里需要注意的:COMP_WORDS 切割方式是按 COMP_WORDBREAKS 进行切割的。所以 test:hello.world 会被当成三个单词 test:hello.world;所以 COMP_CWORD 会增加得比较快。(都是坑=_=)
[root@localhost ~]# echo $COMP_WORDBREAKS
"'@><=;|&(:
  • 所以就有人有这样的需求:删除或者添加 COMP_WORDBREAKS,比如,我希望 . 当成分隔符,或者我希望 : 不是分割符。注意:千万别去改COMP_WORDBREAKS。这里首推 StackOverflow 的帖子,好久远的帖子了。
    • 对于删除分隔符,使用 _get_comp_words_by_ref -n : xxxxx 就可以把因 : 分割的单词拼起来。大家可以百度一下 _get_comp_words_by_ref 这个关键字,印象中有人详解过。
    • 对于添加分隔符,我参考了LinuxQuestions的帖子。思路是,自己把 . 作为分隔符切分,然后作为前缀在单词补全后补上,同时对于其他特殊字符,也可以作为后缀补上。
local pro=($(pwd))
local prefix=${cur%%.*}
cd $dict_path"/"$prefix
compopt -o nospace
COMPREPLY=( $(compgen -S "#" -P $prefix"." -d -f -- ${cur#*"."}) )
cd $pro
  • 将 cur 从右边数最后一个 . 的左边的内容作为前缀,利用 compgen-P 参数,这是增加前缀的参数。如果不加前缀,就会出现 test.f ,你希望 f 补全为 father,整体变成 test.father,这是你希望得到的。请注意,补全是整个单词补全,所以没有前缀的情况下,test.是会被删掉的,你只能得到 father ,所以 test. 必须首先抽出来当做前缀,然后补全得到 father 后拼到前面得到 test.father。(在下语文水平不好,希望描述清楚了这个巨坑)。同理,补全是补全单词,不会带像 cd 命令一样的 /,所以如果想自动补全 /,使用 -S 参数,增加后缀(代码中我增加了 # 后缀)。
  • compopt -o nospace 是将补全后自动加的空格删掉。
补充:/etc/bash_completion.d 目录下的补全脚本不生效

结束语

折腾了两天,全程 tab 起飞,放飞自我。当然其中还学习了一些 shell 命令的基本写法,假装自己是运维。路漫漫其修远兮,加油加油!

Logo

更多推荐