É possível configurar a maneira como o bash conclui os nomes de diretório?

8

Gostaria de instruir o bash a usar um método especial para executar a conclusão em determinados nomes de diretório. Por exemplo, o bash chamaria um programa meu para executar a conclusão se um caminho iniciar com "$$" e, normalmente, executaria a conclusão normalmente.

Tudo isso é possível? Como você o implementaria?

Recompensa : Eu realmente aprecio uma resposta a essa pergunta. O objetivo é permitir que o salto automático complete caminhos para todos os comandos quando o usuário os inicia com um determinado prefixo. Por exemplo, ao copiar um arquivo de um diretório remoto, você pode digitar:

cp $$patern + <Tab>

e o autojump seria concluído

cp /home/user/CompliCatedDireCTOry/long/path/bla/bla

e você apenas teria que adicionar onde deseja colocar o arquivo. É claro que posso usar o comentário de ott para adicioná-lo a alguns comandos específicos, mas se alguém tiver uma idéia melhor, ficaria muito grato.

Peltier
fonte
Consulte a seção "Conclusão programável" na página de manual do bash.
Se você votar para encerrar minha pergunta, explique o motivo.
Peltier
2
"complete" suporta "-G pattern" para corresponder ao seu $$ e ao início e "-F func" para chamar sua própria função, mas ele precisa de um ou mais nomes de comando para funcionar.
Por que não usar apenas uma variável de ambiente? Por exemplo: cp $ prefix / file / path / to / dest /
Xenoactive 09/09
@ Xenoactive: porque o salto automático é totalmente automatizado e funciona em mais de um caminho. Usar variáveis ​​de ambiente definidas manualmente não ajuda. Ou talvez você tenha uma ideia poderosa que eu não entendo?
Peltier

Respostas:

3

Você pode fazer isso substituindo a ligação padrão para TAB (^ i). Primeiro, você precisa substituir a ligação TAB e, em seguida, criar uma função que chama seu comando; por fim, você precisa pegar a saída desse comando e atualizar a variável que contém a linha de comando atual.

Esta função pega a linha de comando atual e altera os dois últimos caracteres para 'huugs'.

function my_awesome_tab_completion_function () {
  set -- $READLINE_LINE
  command="$1"
  shift
  argument="$*"
  argument_length=$(echo -n $argument | wc -c)
  if echo $argument | grep '^$$' >/dev/null 2>&1; then
    new_argument=$(echo $argument | sed 's/..$/huugs/') # put your autojump here
  else
    new_argument=$(compgen -d $argument)
  fi
  new_argument_length=$(echo -n $new_argument | wc -c)
  READLINE_POINT=$(( $new_argument_length - $argument_length + $READLINE_POINT ))
  READLINE_LINE="$command $new_argument"
}

Para o seu exemplo, você provavelmente desejaria alterar a linha new_argument para ficar assim:

  new_argument=$(autojump $argument)

Agora substitua a ligação ^ i:

$ bind -x '"\C-i"':'my_awesome_tab_completion_function'

Agora teste se funciona:

$ cd /ro<TAB>
changes my command to:
$ cd /root

para que a conclusão normal ainda funcione, você pode testar a parte $$ fazendo cd $$ ... etc.

Se você tiver problemas, ative o modo detalhado:

$ set -x

Ele imprimirá tudo o que a função está fazendo.

Eu testei isso no Ubuntu 11 usando o bash 4.2.8 (1) -release (o padrão).

polinomial
fonte
Parece-me que isso funciona apenas no primeiro parâmetro do comando e também pode fazer coisas estranhas se a guia for usada de maneiras inesperadas (por exemplo, após um $$$ ou após o nome do comando), ou estou errado?
harrymc
Bem, está passando $ * para que 'funcione' mais do que apenas o primeiro parâmetro (eu não sei o salto automático, então não tenho certeza se ele pode receber vários argumentos). Você pode mudar para o final e enviar apenas o último para o salto automático, ou usar READLINE_POINT para determinar onde o cursor está entre os argumentos do comando e enviar apenas essa 'palavra' para o salto automático.
polinômio
Sua solução é interessante, mas você deve admitir que assumir a tecla tab é um pouco extremo. Não há como prever todos os casos possíveis.
harrymc 12/09
Obrigado pela sua resposta, essa é uma boa solução alternativa e aborda a parte "de todos os comandos" da minha pergunta. Eu concordo com a harrymc que é um pouco extremo, no entanto ... Acho que se ninguém encontrar uma solução melhor, vou tentar e ver se é viável.
Peltier
Sim, eu concordo com o harrymc também, mas estava tentando responder à pergunta conforme solicitado. Pessoalmente, eu vincularia isso a outra tecla de controle como ^ G ou algo assim, para deixar a guia em paz, mas ainda usar essa funcionalidade.
polinomial
1

A rotina de conclusão do bash pode ser programada como um script de shell.

Aqui está um exemplo de script de shell que será substituído em qualquer parâmetro $$[Tab]por my replacement string, mas apenas para o comando específico mycommande somente se o parâmetro for exatamente "$$":

_mycomplete()
{
        if [ ${COMP_WORDS[COMP_CWORD]} == \$\$ ]
        then
                COMPREPLY='my replacement string'
        fi
}
complete -o default -o bashdefault -F _mycomplete mycommand

Você deve originar o script para bash via source <file-name>(ou o comando dot) para iniciá-lo funcionando e, em seguida:

mycommand $$[Tab] -> mycommand my replacement string
mycommand $$$[Tab] -> mycommand $$$ (beep)
mycommand whatever[Tab] -> (will complete "whatever" in the normal bash manner)

Para que ele funcione sempre para alguns ou todos os usuários, inclua isso em uma das rotinas do perfil do bash .

O problema com o completecomando é que ele funcionará apenas para um ou mais nomes de comandos especificados como parâmetros. Pode-se simplesmente fornecer a lista de todos os comandos que poderiam ser usados ​​pelos usuários ou, em casos desesperados, expandir-se /bin/* /usr/bin/* ~/bin/*.

Testado no CentOS 5.5.

Esse script simples é baseado nas fontes que listei na minha outra resposta - a que foi excluída pelo moderador studiohack. Se estiver interessado, peça-lhe para cancelar a exclusão.

harrymc
fonte
Obrigado pela sua resposta. Minha pergunta não era realmente sobre isso, já que eu era nova, era possível, mas não conclui todos os comandos. No entanto, acho que, se a solução do polinômio não for aceitável, implementarei algo assim e tentarei direcionar os comandos mais comuns.
Peltier