2015-04-19 131 views
5

我正在嘗試編寫一個Bash完成腳本,用於在--option--param=value表單上可以使用長選項的命令。如果用戶已經在命令行中輸入了一個選項,那麼該選項應該從完成列表中排除(假設只在命令行上指定一個給定的選項纔有意義)。帶等號的完整命令選項

這是第一次嘗試:

_myprog() 
{ 
    local cur="${COMP_WORDS[$COMP_CWORD]}" 

    local words=(--help --param1= --param-state --param2=) 
    _exclude_cmd_line_opts 
    COMPREPLY=($(compgen -W "${words[*]}" -- "$cur")) 
} 
complete -F _myprog myprog 

_exclude_cmd_line_opts() { 
    local len=$(($COMP_CWORD - 1)) 
    local i 
    for i in "${COMP_WORDS[@]:1:$len}" ; do 
     [[ $i == --* ]] && words=("${words[@]/$i}") 
    done 
} 

如果source這個腳本source script.sh然後寫:

$ myprog --param1= <tab><tab> 

我碰到下面的完成列表:

=    --help   --param2=  --param-state 

所以它的工作原理幾乎除了我得到一個虛假'='登錄完成lis任何建議?

+1

在'local words'賦值中將'--param1 ='改爲'--param1'。 – Barmar

+0

是的,但我想避免讓用戶在可能的情況下輸入'='符號。 –

+0

哦,你在開頭討論'=',而不是在'--param2之後的'=' '。我以前沒有看到過。 – Barmar

回答

2

由於COMP_WORDBREAKS的默認內容,在命令行中輸入等號會強制執行分詞。效果似乎是等號在COMP_WORDS中作爲單獨的詞輸入。這是在_exclude_cmd_line_opts以下修改剝削:

_exclude_cmd_line_opts() { 
    local len=$(($COMP_CWORD - 1)) 
    local i 
    for ((i=1 ; i<=len; i++)) ; do 
     local j="${COMP_WORDS[$i]}" 
     if [[ $j == --* ]] ; then 
      ((i<len)) && [[ ${COMP_WORDS[$((i + 1))]} == '=' ]] && j="$j=" 
      words=("${words[@]/$j}") 
     fi 
    done 
} 

與原始版本的_exclude_cmd_line_opts${words[@]/$j}會給一個虛假=的問題時,例如words=(param1=)j="param1"(注意$j失蹤後等號這是通過COMP_WORDBREAKS引起的)..

更新

我發現了另一個特點 有了這個。上述情況正常工作,因爲我從來不必在=符號後立即輸入<tab>。但是,例如,如果words=(--param= --param-info)和I類型--par<tab>仍然有兩個候選完成,並且當前單詞只部分完成爲--param。在這裏,我想選擇兩個候選者中的第一個,並且我在命令行上鍵入明確的=符號,然後鍵入<tab>現在發生的事情是Bash認爲您鍵入了一個空格(因爲COMP_WORDBREAKS包含=)並且當前完成字從--param=更改爲=。這又會讓Bash readline省略插入通常的空間,所以用戶被迫鍵入一個空格繼續完成下一個選項。

通過返回一個空字符串的COMPREPLY數組,可以避免必須在上述情況下輸入空格。

_myprog() 
{ 
    local cur="${COMP_WORDS[$COMP_CWORD]}" 
    local prev="" 
    ((COMP_CWORD > 0)) && prev="${COMP_WORDS[$((COMP_CWORD - 1))]}" 
    [[ $cur == '=' && $prev == --* ]] && { COMPREPLY=(""); return; } 

    local words=(--param= --param-info) 
    _exclude_cmd_line_opts 
    COMPREPLY=($(compgen -W "${words[*]}" -- "$cur")) 
} 
+0

這是什麼我也會這樣做。 (我玩過,但你早些時候回答。):)另外,似乎沒有其他方式,然後後衛生這一點,因爲你已經提到設置'COMP_WORDBREAKS'可能會影響其他程序的行爲。 – hek2mgl