Shell腳本中實現自動補全功能

對於Linuxer來講,自動補全是再熟悉不過的一個功能了。當你在命令行敲下部分的命令時,確定會本能地按下Tab鍵補全完整的命令,固然除了命令補全以外,還有文件名補全。html

Bash-completion

自動補全這個功能是Bash自帶的,但通常咱們會安裝bash-completion包來獲得更好的補全效果,這個包提供了一些現成的命令補全腳本,一些基礎的函數方便編寫補全腳本,還有一個基本的配置腳本。但也正如以前說的,這個包不是必須的,只不過能夠省些力氣。web

bash-completion這個包的安裝位置因不一樣的發行版會有所區別,可是大體上啓用的原理是相似的,通常會有一個名爲bash_completion的腳本,這個腳本會在shell初始化時加載。例如對於RHEL系統來講,這個腳本位於/etc/bash_completion,而該腳本會由/etc/profile.d/bash_completion.sh中導入:shell

 

 1 # Check for interactive bash and that we haven't already been sourced.
 2 [ -z "$BASH_VERSION" -o -z "$PS1" -o -n "$BASH_COMPLETION" ] && return  3 
 4 # Check for recent enough version of bash.  5 bash=${BASH_VERSION%.*}; bmajor=${bash%.*}; bminor=${bash#*.}  6 if [ $bmajor -gt 3 ] || [ $bmajor -eq 3 -a $bminor -ge 2 ]; then
 7     if shopt -q progcomp && [ -r /etc/bash_completion ]; then
 8  # Source completion code.  9         . /etc/bash_completion 10     fi
11 fi
12 unset bash bmajor bminor

 

而在bash_completion腳本中會加載/etc/bash_completion.d下面的補全腳本:數組

 

if [[ $BASH_COMPLETION_DIR != $BASH_COMPLETION_COMPAT_DIR && \ -d $BASH_COMPLETION_DIR && -r $BASH_COMPLETION_DIR && \ -x $BASH_COMPLETION_DIR ]]; then
    for i in $(LC_ALL=C command ls "$BASH_COMPLETION_DIR"); do i=$BASH_COMPLETION_DIR/$i [[ ${i##*/} != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) \ && -f $i && -r $i ]] && . "$i"
    done
fi unset i

 

補全腳本的名稱通常就是命令名,這樣比較容易查找:bash

 

$ ls i* iconv iftop ifupdown info  iproute2  iptables

 

內置補全命令

Bash內置有兩個補全命令,分別是compgencompletecompgen命令根據不一樣的參數,生成匹配單詞的候選補全列表,例如:函數

 

$ compgen -W 'hi hello how world' h hi hello how

 

compgen最經常使用的選項是-W,經過-W參數指定空格分隔的單詞列表。h即咱們在命令行當前鍵入的單詞,執行完後會輸出候選的匹配列表,這裏是以h開頭的全部單詞。spa

complete命令的參數有點相似compgen,不過它的做用是說明命令如何進行補全,例如一樣使用-W參數指定候選的單詞列表:.net

 

$ complete -W 'word1 word2 word3 hello' foo $ foo w<Tab> $ foo word<Tab> word1 word2 word3

 

咱們還能夠經過-F參數指定一個補全函數:命令行

 

$ complete -F _foo foo

 

如今鍵入foo命令後,會調用_foo函數來生成補全的列表,完成補全的功能,這一點正是補全腳本實現的關鍵所在,咱們會在後面介紹。code

補全相關的內置變量

除了上面的兩個補全命令外,Bash還有幾個內置的變量用來輔助補全功能,這裏主要介紹其中三個:

  • COMP_WORDS: 類型爲數組,存放當前命令行中輸入的全部單詞;
  • COMP_CWORD: 類型爲整數,當前光標下輸入的單詞位於COMP_WORDS數組中的索引;
  • COMPREPLY: 類型爲數組,候選的補全結果;
  • COMP_WORDBREAKS: 類型爲字符串,表示單詞之間的分隔符;
  • COMP_LINE: 類型爲字符串,表示當前的命令行輸入;

例如咱們定義這樣一個補全函數_foo:

 

$ function _foo() { echo -e "\n" declare -p COMP_WORDS declare -p COMP_CWORD declare -p COMP_LINE declare -p COMP_WORDBREAKS } $ complete -F _foo foo

 

假設咱們在命令行下輸入如下內容,再按下Tab鍵補全:

 

$ foo b declare -a COMP_WORDS='([0]="foo" [1]="b")' declare -- COMP_CWORD="1" declare -- COMP_LINE="foo b" declare -- COMP_WORDBREAKS="

 

對着上面的結果,我想應該比較容易理解這幾個變量。固然正如咱們以前聽說,Bash-completion包並不是是必須的,補全功能是Bash自帶的。

編寫腳本

補全腳本分紅兩個部分:編寫一個補全函數和使用complete命令應用補全函數。後者的難度幾乎忽略不計,重點在如何寫好補全函數。難點在,彷佛網上不多與此相關的文檔,可是事實上,Bash-completion自帶的補全腳本是最好的起點,能夠挑幾個簡單的改改基本上就可使用了。

通常補全函數(假設這裏依然爲_foo)都會定義如下兩個變量:

 

local cur prev

 

其中cur表示當前光標下的單詞,而prev則對應上一個單詞:

 

cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}"

 

初始化相應的變量後,咱們須要定義補全行爲,即輸入什麼的狀況下補全什麼內容,例如當輸入-開頭的選項的時候,咱們將全部的選項做爲候選的補全結果:

 

local opts="-h --help -f --file -o --output"

if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0
fi

 

不過再給COMPREPLY賦值以前,最好將它重置清空,避免被其它補全函數干擾。

如今完整的補全函數是這樣的:

 

function _foo() { local cur prev opts COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" opts="-h --help -f --file -o --output"

    if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0
    fi }

 

如今在命令行下就能夠對foo命令進行參數補全了:

 

$ complete -F _foo foo $ foo -
-f        --file    -h        --help    -o        --output

 

固然,彷佛咱們這裏的例子沒有用到prev變量。用好prev變量可讓補全的結果更加完整,例如當輸入--file以後,咱們但願補全特殊的文件(假設以.sh結尾的文件):

case "${prev}" in
    -f|--file) COMPREPLY=( $(compgen -o filenames -W "`ls *.sh`" -- ${cur}) ) ;; esac

 

如今再執行foo命令,--file參數的值也能夠補全了:

 

$ foo --file<Tab> a.sh b.sh c.sh

 

安裝補全腳本

若是安裝了Bash-completion包,能夠將補全腳本放在/etc/bash_completion.d目錄下,或者放到~/.bash_completion文件中。
若是沒有安裝Bash-completion包,能夠把補全腳本放到~/.bashrc或者其它能被shell加載的初始化文件中。

 

原文地址 http://www.it165.net/os/html/201212/4208.html

相關文章
相關標籤/搜索