É possível configurar a forma como o bash completa os nomes dos diretórios?

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 começar com "$$" e executar a conclusão normalmente, de outra forma.

Isso é possível? Como você implementaria isso?

Recompensa : Eu realmente aprecio uma resposta para essa pergunta. O objetivo é permitir que o autojump conclua 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 distante, você pode digitar:

cp $$patern + <Tab>

e o autojump completaria

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

e você teria apenas 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 ideia melhor, ficarei muito grato.

    
por Peltier 07.09.2011 / 13:11

2 respostas

3

Você pode fazer isso substituindo a ligação padrão para TAB (^ i). Primeiro você precisa sobrescrever a ligação TAB, então você precisa construir uma função que chame seu comando, por último você precisa pegar a saída desse comando e atualizar a variável que contém a linha de comando atual.

Esta função assume 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 desejará 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 que funciona:

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

assim a conclusão normal ainda funciona, 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).

    
por 10.09.2011 / 22:11
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 substituirá em qualquer parâmetro $$[Tab] by my replacement string , mas somente para o comando específico mycommand e 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 fornecer o script para bash via source <file-name> (ou o comando dot) para iniciá-lo 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 sempre funcionar para alguns ou todos os usuários, inclua isso em uma das rotinas de perfil bash .

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

Testado no CentOS 5.5.

Este script simples é baseado nas fontes que eu listei na minha outra resposta - aquela que foi apagada pelo moderador studiohack. Se estiver interessado, basta pedir a ele para desfazer a exclusão.

    
por 11.09.2011 / 00:08