2015-04-19 9 views
5

Sto provando a scrivere uno script di completamento Bash per i comandi che possono richiedere opzioni lunghe nel modulo --option o --param=value. Se l'utente ha già inserito un'opzione sulla riga di comando, tale opzione deve essere esclusa dalla lista di completamento (assumendo che abbia senso solo specificare una determinata opzione una volta sulla riga di comando).Opzioni di comando complete con segno di uguale

Ecco un primo tentativo:

_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 
} 

Se sorgente di questo script source script.sh e poi scrivere:

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

ottengo il seguente elenco di completamento:

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

così funziona quasi tranne che ottengo un segno spuria '=' nel completamento lis t .. Qualche suggerimento?

+1

Modifica '--param1 =' a '--param1' nell'assegnazione' local words'. – Barmar

+0

Sì, funziona, ma vorrei evitare che l'utente digiti il ​​segno '=' se possibile .. –

+0

Oh, stai parlando di '=' all'inizio, non di '=' dopo '--param2 '. Non l'ho visto prima. – Barmar

risposta

2

Immissione di un segno di uguale sulla riga di comando impone un'interruzione di parola a causa del contenuto predefinito di COMP_WORDBREAKS. L'effetto sembra essere che il segno di uguale viene immesso come parola separata in COMP_WORDS. Ciò è sfruttato nel seguente modifica di _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 
} 

Il problema con la versione originale di _exclude_cmd_line_opts era che ${words[@]/$j} darebbe una spuria = quando ad esempio words=(param1=) e j="param1" (notare il segno di uguale mancante finale nel $j che era causata da COMP_WORDBREAKS) ..

Aggiornamento

ho scoperto un'altra peculiarità con questo. I casi sopra funzionati bene perché non ho mai dovuto digitare <tab> immediatamente dopo un segno =. Tuttavia, se ad esempio words=(--param= --param-info) e I digitare --par<tab> ci sono ancora due completamenti candidati e le parole correnti sono completate solo parzialmente per diventare --param. A questo punto vorrei selezionare il primo dei due candidati e digitare un segno esplicito = sulla riga di comando e digitare <tab> ciò che accade ora è che Bash pensa di aver digitato uno spazio (poiché COMP_WORDBREAKS contiene =) e la parola di completamento corrente cambia da --param= a =. Questo di nuovo, farà sì che Bash readline ometti di inserire il solito spazio, quindi l'utente è costretto a digitare uno spazio per continuare a completare l'opzione successiva.

È possibile evitare di digitare uno spazio nel caso precedente, restituendo un array COMPREPLY con una stringa vuota.

_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

Questo è ciò che Anch'io lo farei. (Ho giocato in giro ma hai risposto prima.) :) Inoltre sembra che non ci sia altro modo quindi di post-sanitizzare questo, dal momento che hai già detto che l'impostazione di 'COMP_WORDBREAKS 'potrebbe influenzare il comportamento di altri programmi. – hek2mgl

Problemi correlati