在下所在的公司定義了一種路徑,配合自定義的 loader 命令;遂命令在下完成自定義路徑的自動補全需求。
關於Linux Shell命令自動補全已有的一些優秀 blog
- 沒有開花的樹的《詳解Linux Shell命令自動補全》
- 這篇文章講得比較系統,最後給的 demo 也特別優秀。
- Linux中10個關於命令行自動補全的技巧
- 注意這篇文章中的第10條:如果定義的補全規則沒有生成匹配時,可以使用 -o 選項生成補全。強烈建議使用
-o default
,這樣在沒有補全項的情況下可以走系統默認的。
- 注意這篇文章中的第10條:如果定義的補全規則沒有生成匹配時,可以使用 -o 選項生成補全。強烈建議使用
- 【Bash百寶箱】shell命令行自動補全(compgen、complete、compopt)
- 這篇文章的參數詳解非常值得參考。
本人遇到的一些需求及解決方案:
需求一:從多個路徑下獲取補全候選項,並做去重
- 解決方案寫一個循環獲取所有候選項,並且去重。這裏記錄一下 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 目錄下的補全腳本不生效
- 有可能遇到將腳本放到
/etc/bash_completion.d
目錄下不生效的情況,原因可能是:缺少/etc/profile.d/bash_completion.sh
(根據爲什麼/etc/bash_completion.d 下面的bash自動補全腳本不生效)
結束語
折騰了兩天,全程 tab 起飛,放飛自我。當然其中還學習了一些 shell 命令的基本寫法,假裝自己是運維。路漫漫其修遠兮,加油加油!