Como editar a conclusão do comando para ssh no zsh?

11

Gostaria de configurar a conclusão do comando no zsh para exibir os nomes de host depois de digitar

ssh [TAB]

retirando os nomes do meu arquivo .ssh / config (e de preferência de known_hosts e / etc / hosts e em qualquer outro lugar que faça sentido) e apresentando uma única lista.

Faz parte disso atualmente, mas

  1. ele não usa .ssh / config
  2. requer primeiro um nome de usuário, embora o uso de .ssh / config torne desnecessário digitar nomes de usuário
  3. apresenta várias listas (provavelmente uma de known_hosts e outra de / etc / hosts, mas não verifiquei isso)

Então, quero incluir nomes de usuário conhecidos e nomes de host conhecidos na lista (de preferência única) depois de digitar ssh [TAB]

(Estou chegando aqui antes do Google porque 1) resultará na resposta armazenada aqui e 2) é provavelmente mais eficiente. Se ninguém mais responder, vou procurar a resposta.)

iconoclasta
fonte
Isso seria uma pergunta para superusuário, eu acho
Etienne Perot
Na verdade, olhando agora, eu deveria ter perguntado no unix.stackexchange.com. (Mas não me lembro se isso foi há cerca de 2 anos quando eu pedi.) Alguém quer migrar?
Iconoclast

Respostas:

16

Aqui está a parte relevante da minha .zshrc. Não mudou desde 2002, por isso posso escrever de forma diferente hoje, mas ainda funciona para completar os nomes de host ~/.ssh/confige ~/.ssh/known_hosts(se HashKnownHostsestiver desativado - não existia naqueles dias).

h=()
if [[ -r ~/.ssh/config ]]; then
  h=($h ${${${(@M)${(f)"$(cat ~/.ssh/config)"}:#Host *}#Host }:#*[*?]*})
fi
if [[ -r ~/.ssh/known_hosts ]]; then
  h=($h ${${${(f)"$(cat ~/.ssh/known_hosts{,2} || true)"}%%\ *}%%,*}) 2>/dev/null
fi
if [[ $#h -gt 0 ]]; then
  zstyle ':completion:*:ssh:*' hosts $h
  zstyle ':completion:*:slogin:*' hosts $h
fi
Gilles 'SO- parar de ser mau'
fonte
Ok, finalmente descobri por que isso não estava funcionando. O problema não estava no código fornecido: ele funciona bem quando o outro problema foi resolvido.
Iconoclast
1

A função que fornece a sshconclusão está localizada /usr/share/zsh/functions/Completion/Unix/_sshem meu sistema.

Consulte também man zshcompsysa documentação (especialmente faça uma pesquisa em "host" que aparece em vários locais e "ssh" que aparece em alguns locais).

Pode ser possível que a adição de um zstylecomando ao seu ~/.zshrcfaça o que você está procurando sem precisar modificar a função de conclusão.

Pausado até novo aviso.
fonte
Ou no /usr/share/zsh/4.3.9/functions/_sshMac OS X (adapte a versão)
Studer
Eu origino esse arquivo, digite ssh <TAB> e obtenho a conclusão do nome do arquivo. O que há com isso?
Iconoclast
1

Eu faço isso usando uma lista de todos os hosts em um determinado domínio usando dig. Você pode substituir a função abaixo por qualquer sistema de pesquisa que desejar, incluindo o arquivo hosts ou uma lista estática:

function complete_host_from_zone () {
    reply=(`dig axfr ouraynet.com @ns1.ouraynet.com | grep -e '^[a-z]' | cut -d\. -f1`)
}
compctl -x 'p[1]' -K complete_host_from_zone -- ssh

Nota: O código acima pode não substituir completamente o sistema completo do comando ssh em sua configuração. Se você tiver problemas, tente alterar o comando "ssh" para outro comando aleatório como "mycompletetest" e verifique se a conclusão funciona para isso.

Observe também que isso transfere a zona DNS a cada conclusão! Se você usar muito isso ou em um domínio estático, faria sentido fazer a pesquisa e salvar o resultado; em sua função de pesquisa, basta definir reply = zone_result.

Caleb
fonte
Não consigo fazer isso funcionar. Obviamente, tenho que alterar a parte da resposta, mas você pode dar um exemplo prático com texto estático, para que eu saiba em que formato deve estar? (Eu tentei o que eu entendi a página de homem para dizer, e corrigido -k a K, e ainda não funcionou.)
iconoclasta
O formato da resposta é bastante simples, é apenas um blob de texto direto, uma possível resposta por linha. O problema do DNS é provavelmente a parte mais complicada. Seu servidor DNS precisa oferecer suporte à transferência de zona para que isso funcione. Isso geralmente significa que você precisa estar conversando com o servidor DNS primário do domínio em questão, assim dig axfr mydomain.com @ns1.mydomain.com. Certifique-se de poder executar isso manualmente e parte da saída deve ser uma lista de hosts registrados nesse domínio e seus A ou qualquer outro registro. Era para isso que eu estava procurando, depois cortando apenas a parte do nome do host e não o registro totalmente qualificado.
Caleb
Observe que reescrevi o código de exemplo na minha resposta para estar funcionando de forma completa, incluindo um nome de domínio para o qual a pesquisa de transferência de zona funciona. Você pode então adaptar para o conjunto. Peço desculpas pelo original, que acabou com dois erros de digitação de quando rasguei cerca de 20 camadas extras de coisas que estavam no meu arquivo .zshrc que não são relevantes para este exemplo.
Caleb
O comando dig no backticks funciona agora (obrigado por editá-lo!), Mas não mostra nenhum dos resultados desse comando quando digito ssh <TAB>. Existe algo mais fora disso que precisa ser ativado antes de funcionar?
Iconoclast
0

Eu gosto de manter meu known_hostsarquivo hash e prefiro não HashKnownHostsdesligar. Eu descobri que semear o que @Gilles tem com o que já está na minha história tem sido bastante eficaz para minhas necessidades.

h=($(echo $(history | awk '{print $4 " " $5 "\n"}' | grep 'ssh ' | awk '{print $2}' | sort -u)))
if [[ -r ~/.ssh/config ]]; then
  h=($h ${${${(@M)${(f)"$(cat ~/.ssh/config)"}:#Host *}#Host }:#*[*?]*})
fi
if [[ -r ~/.ssh/known_hosts ]]; then
   h=($h ${${${(f)"$(cat ~/.ssh/known_hosts{,2} || true)"}%%\ *}%%,*}) 2>/dev/null
fi
if [[ $#h -gt 0 ]]; then
  zstyle ':completion:*:ssh:*' hosts $h
  zstyle ':completion:*:slogin:*' hosts $h
fi

Além disso, FWIW, é isso que eu usei para o Bash:

# SSH Autocompletion
complete -W "
  $(echo $(grep '^\s*ssh ' ~/.bash_history | sort -u | sed 's/^ssh //' | awk '{print $1}'))
  $(echo $(history | awk '{print $2 " " $3}' | grep 'ssh ' | awk '{print $2}' | sort -u))
  $(sed 's/#.*//;' ~/.ssh/config | awk ' /^Host (.+)$/ {$1 = "";print tolower($0)}')
" ssh
Karl Wilbur
fonte