2013年12月14日 星期六

bash autocomplete 實作教學

最近在練習寫 bash 的指令自動補完。就是按兩下 Tab 就會把可以用的東西列出來,並且如果列出來的東西都有相同的開頭,他還會自動幫你補完,一直補到不一樣的東西為止。

開始開發以後,才發現這真的是 bash 自己提供的功能,相關產生名單的機制他也有指令可以幫你做好。

其實一般而言,要補完的東西不外乎這幾樣:
  • 檔名 & 目錄
  • 可用的命令與參數
  • 連線的機器
這些東西其實 bash 都已經有 compgen 指令幫我們做好了,我們只要拿來用就可以了。

另外要熟悉的是在 bash script 中,陣列的操作方式。

如何使用 compgen 

語法


compgen [參數] [清單] -- [目前已經輸入的內容]

補完自訂清單 (-W)


這是最常使用的功能。假設你有以下四個指令 list arg1 arg2 ls。你目前已經輸入 arg。那可以在 bash 環境下面試試看:

$ compgen -W "list arg1 arg2 ls" -- arg
arg1
arg2
$

補完目錄 (-d)


假設你有 dir1/ 和 dir2/ 兩個目錄,目前已經輸入 di。可以在 bash 環境下試試看:
$ compgen -d -- di
dir2
dir1
$

補完檔案 (-f)


假設目前有這六個檔案  file11  file12  file21  file22  text1.txt  text2.txt。可以在 bash 環境下試試:
  • 列出 file 開頭檔案: compgen -f -- file
  • 列出 txt 副檔名的檔案: compgen -f -X '!*.txt' --

補完機器清單 (-A) 

  1. 建立一個機器清單文字檔,一行一個 hostname。假設我們有以下機器:
    • host11.test.com
    • host12.test.com
  2. 把文字檔路徑指定到 HOSTFILE 環境變數
    • export HOSTFILE=~/testarea/hostlist
  3. $ compgen -A hostname -- ho

撰寫產生 list 的 bash function

讓我們看一下最簡單的範例。補完指令 --help --verbose --version。
(範例來自 www.debian-administration.org) 
_foo() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts="--help --verbose --version"

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

我們產生了 _foo() 含式,並且用 complete 這個指令告訴 bash, foo 這個指令可以用 _foo() 這個含式來產生自動補完清單。

讓我們看一下 _foo() 裡面有哪些是重要的變數。
  • COMP_CWORD: 目前所在的 index
  • COMP_WORDS: user 輸入的指令 array
  • COMPREPLY: 產生出來的可用指令的 array。
$cur 就是目前使用者輸入的最後一個字。$prev 就是使用者輸入的前一個字。

剩下的,就是 bash 中複雜的 array 寫法了。
 

參考資料

  • http://www.debian-administration.org/article/317/An_introduction_to_bash_completion_part_2

沒有留言:

張貼留言