Como usar a opção completa ou comp - -C do bash (comando)?

4

Ao criar a funcionalidade de conclusão de shell no bash, parece que a opção -C seria poderosa e comum. Está definido assim:

-C command

command is executed in a subshell environment, and its output is used as the possible completions.

Isso parece muito simples. Mas, estranhamente, não é. Se eu fizer:

$ complete -C "echo one two three" test.sh

e, em seguida, digite test.sh e pressione [tab] uma vez, eu recebo a linha preenchida com

$ test.sh one two three test.sh  test.sh

de volta. O que?! Para comparação,

$ complete -W "one two three" test.sh

faz exatamente o que eu esperava: oferece um , três , ou dois possíveis conclusões (em ordem de classificação, é claro ).

Não consigo encontrar nenhuma boa documentação em nenhum lugar, então estou experimentando ... talvez um ponto-e-vírgula ajude? complete -C "echo one two three;" test.sh ... Ah, ok, isso ajuda alguns , porque remove aquele test.sh estranho do final. Mas ainda preenche a string completa one two three . Isso é estranho, porque essa descrição acima definitivamente diz "completações possíveis", plural. ... então, hmmm, ah, novas linhas? Vamos tentar complete -C "echo -e 'one\ntwo\nthree';" test.sh .

Ok, isso é promissor. Se eu digitar test.sh [tab] , recebo de volta one three two . Mas então, as coisas dão errado. Eu adiciono um o para resolver a ambigüidade, então, test.sh o[tab] e que retorna

o      one    three  two

O que é intrigante. Na verdade, qualquer string que eu digitar será adicionada à lista; se eu fizer test.sh wtf[tab] , receberei one three two wtf retornado. Eu acho que possivelmente eu preciso fazer algo sofisticado com compgen , mas, novamente, eu enfatizo, isso funciona como esperado com -W . E, de fato,

$ complete -W '$(echo one two three)' test.sh

funciona muito bem (observe aspas simples para evitar a expansão / execução prematura, caso você faça algo mais sofisticado que echo , o que poderia produzir resultados variáveis).

O que estou perdendo aqui?

    
por mattdm 18.12.2015 / 18:35

1 resposta

5

É o trabalho do comando -C descobrir qual texto inserir em resposta a uma solicitação de conclusão. A interface é um pouco estranha:

  • O argumento para -C é interpretado como um trecho de script bash. O Bash anexa três strings com aspas corretamente a este snippet:

    • o comando cujos argumentos estão sendo concluídos;
    • o prefixo da palavra onde o cursor está, até o cursor;
    • a palavra antes do cursor.
  • Algumas variáveis são adicionadas ao ambiente:

    • COMP_LINE contém a linha completa na qual a conclusão é executada.
    • COMP_POINT contém a posição do cursor dentro de COMP_LINE (contando de 0) .
    • COMP_TYPE é 9 para conclusão normal, 33 ao listar alternativas em conclusões ambíguas , 37 para conclusão do menu, 63 ao tabular entre conclusões ambíguas, 64 para listar conclusões após uma conclusão parcial.
    • COMP_KEY contém a chave que desencadeou a conclusão (por exemplo, um caractere de tabulação se o usuário pressionou a tecla Tab ).
  • A saída do comando é interpretada como texto para substituir a palavra atual por. Note que este é um substituto, não um sufixo para acrescentar; o comando é suposto filtrar pelo prefixo dado. Pode conter várias linhas e, nesse caso, cada linha é considerada uma possível substituição.

Este é basicamente o mesmo mecanismo que é fornecido e melhor documentado , para funções com -F . As funções obtêm uma interface um pouco mais simples: elas podem ler a lista de palavras do comando atual no variável COMP_WORDS e a posição inicial da palavra atual em COMP_CWORD ; eles escrevem os resultados na matriz COMP_REPLY .

Como os argumentos úteis - em particular, o prefixo para completar - são passados no final do comando, -C é praticamente utilizável apenas com um comando externo. Claro que você pode usar algo como sh -c … , mas não será bonito.

complete -C 'sh -c '\'for x in one two three; do case $x in "$1"*) echo "$x";; esac''\'
    
por 20.12.2015 / 04:06