1. 程式人生 > >詳解Linux Shell命令自動補全

詳解Linux Shell命令自動補全

在Linux命令列下,輸入字元後,按兩次Tab鍵,shell就會列出以這些字元打頭的所有可用命令。如果只有一個命令匹配到,按一次Tab鍵就自動將這個命令補全。比如,想更改密碼,但只記得這個命令前幾個字母是pass。這時候,按Tab鍵,shell就自動輸出 passwd 命令,非常方便。

當然,除了命令補全,還有路徑、檔名補全。這個在我們 cd 到特定目錄時特別好用。

命令補全效果,如下:


那麼,自己開發的程式,該怎麼實現Tab自動補全?

補全命令說明

自動補全是Bash自帶的一個強大的功能,允許通過編碼指定命令引數如何補全。通常,補全指令碼會放在/etc/bash_completion.d/ 目錄下,方便統一啟用所有補全指令碼。這裡例子的命令為 foo
# cat /etc/bash_completion.d/foo.bash
_foo()
{
    local cur=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=( $(compgen -W "exec help test" -- $cur) )
}
complete -F _foo foo

如下,測試foo命令是否自動補全
# chmod +x /etc/bash_completion.d/foo.bash
# source /etc/bash_completion.d/foo.bash
# foo [Tab][Tab]
exec  help  test  
以上,source是為了這個foo.bash在當前會話生效。預設情況下,這個補全指令碼不會被執行到,也就是說,補全命令未啟用。需要source啟用這個指令碼,就可以沒有顧慮地使用了。為了避免每次都要source一次,可以在bashrc加上這個命令。bashrc全域性配置在不同 linux 發行版可能位置不同,如下:
Centos/etc/bashrc
Ubuntu/etc/bash.bashrc
(如果只在當前帳號生效,只要配置 ~/.bashrc 即可)在bashrc檔案末尾加上 source /etc/bash_completion.d/foo.bash,這樣,每次登入到linux後,就會啟用這個補全指令碼。

補全命令詳解

前面給大家演示的例子,用到兩個命令complete和compgen,下面分別介紹這兩個命令。

complete (補全命令)

這是命令補全最核心的命令了,來看下這個命令的引數說明。
# help complete
complete: complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G globpat] [-W wordlist]  [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]
重點說明:
-F function執行shell 函式,函式中生成COMPREPLY作為候選的補全結果
-C command將 command 命令的執行結果作為候選的補全 結果
-G pattern將匹配 pattern的檔名作為候選的補全結果
-W wordlist分割 wordlist 中的單詞,作為候選的補全結果
-p [name]列出當前所有的補全命令
-r [name]刪除某個補全命令
演示下:
# complete -W 'word1 word2 word3 test' foo
# foo w<Tab>
# foo word<Tab>
# complete -p
complete -W 'word1 word2 word3 test' foo
complete -o filenames -F __udisks udisks
# complete -r foo
# complete -p
complete -o filenames -F __udisks udisks

compgen(篩選命令)

這個命令,用來篩選生成 匹配單詞的 候選補全結果
# help compgen
compgen: compgen [-abcdefgjksuv] [-o option]  [-A action] [-G globpat] [-W wordlist]  [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]
重點說明:
-W wordlist分割 wordlist 中的單詞,生成候選補全列表
# compgen -W 'word1 word2 test' 
word1
word2
test
# compgen -W 'word1 word2 test' word 
word1
word2


compopt(修改補全命令設定)

這個命令可以修改補全命令設定,注意了,這個命令必須在補全函式中使用,否則會報錯。
# help compopt
compopt: compopt [-o|+o option] [-DE] [name ...]
重點說明:
+o option啟用 option 配置
-o option棄用 option 配置
例如,設定命令補全後不要多加空格,方法如下:compopt -o nospace

內建補全變數

除了上面三個命令外,Bash還有幾個內建變數來輔助補全功能,如下:
COMP_WORDS型別為陣列,存放當前命令列中輸入的所有單詞
COMP_CWORD型別為整數,當前輸入的單詞在COMP_WORDS中的索引
COMPREPLY型別為陣列,候選的補全結果
COMP_WORDBREAKS型別為字串,表示單詞之間的分隔符
COMP_LINE型別為字串,表示當前的命令列輸入字元
COMP_POINT型別為整數,表示游標在當前命令列的哪個位置

命令列補全例項

下面再結合前面三個補全命令(complete/compgen/compopt)和內建變數,寫了例子說明下。
# cat /etc/bash_completion.d/foo.bash 
_foo()
{
    COMPREPLY=()
    local cur=${COMP_WORDS[COMP_CWORD]};
    local cmd=${COMP_WORDS[COMP_CWORD-1]};
    case $cmd in
    'foo')
          COMPREPLY=( $(compgen -W 'help test read' -- $cur) ) ;;
    'test')
          local pro=( $(awk '{print $1}' /data/a.txt) )
          COMPREPLY=( $(compgen -W '${pro[@]}' -- $cur) ) ;;
    '*')
          ;;
    esac
    if [[ "${COMP_WORDS[1]}" == "read" && ${COMP_CWORD} -eq 2 ]]; then
          local pro=($(pwd))
          cd /data
          compopt -o nospace
          COMPREPLY=($(compgen -d -f -- $cur))
          cd $pro
    fi
    return 0
}
complete -F _foo foo
例子中, foo有3個引數,分別是 help, read, testread 測試遍歷 /data 目錄下所有檔案test 測試從檔案中提取2級引數
help 只是演示,沒有特殊作用現在跑下這個例子:
# mkdir /data
# touch /data/a.txt
# touch /data/b.txt
# tree /data
/data
├── a.txt
└── b.txt

0 directories, 2 files
# source /etc/bash_completion.d/foo.bash 
# foo [Tab][Tab]
help  read  test  
# echo world1 >> /data/a.txt
# echo world2 >> /data/a.txt
# foo test world[Tab][Tab]
world1  world2  
# foo read[Tab][Tab]
a.txt  b.txt


參考:http://blog.csdn.net/mycwq/article/details/52420330
https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.htmlhttp://kodango.com/bash-competion-programminghttp://unix.stackexchange.com/questions/55520/create-bash-completion-script-to-autocomplete-paths-after-is-equal-signhttps://devmanual.gentoo.org/tasks-reference/completion/index.html