Autocompletar nombres de servidor para SSH y SCP

61

Tengo algunos servidores configurados ~/.ssh/config, como alphay beta. ¿Cómo puedo configurar Bash de modo que los comandos ssh al<tab>y scp file.tgz al<tab>autocompletar los nombres de los servidores configurados?

No quiero agregar los servidores a otro archivo (es decir, una matriz Bash) cada vez que se agrega uno, ya que agregamos y eliminamos servidores regularmente y la lista es bastante grande.

dotancohen
fuente
2
¿Tiene el paquete bash-completions instalado para su distribución? Creo que esto es parte de las rutinas de finalización estándar, aunque podría confundirlo con zsh.
Caleb
Mi instalación hace exactamente esto.
slm
Esto está en Kubuntu 12.10, y lo he bash-completioninstalado.
dotancohen

Respuestas:

64

¡¡Lo encontré!!

Parece que en Ubuntu las entradas ~/.ssh/known_hostsestán en hash , por lo que la finalización de SSH no puede leerlas. Esto es una característica, no un error. Incluso mediante la adición HashKnownHosts noa ~/.ssh/config, y /etc/ssh/ssh_configno pude evitar que el hash de acogida.

Sin embargo, los hosts que me interesan también se encuentran en ~/.ssh/config. Aquí hay un script para Bash Completion que lee las entradas de ese archivo:

_ssh() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts=$(grep '^Host' ~/.ssh/config ~/.ssh/config.d/* 2>/dev/null | grep -v '[?*]' | cut -d ' ' -f 2-)

    COMPREPLY=( $(compgen -W "$opts" -- ${cur}) )
    return 0
}
complete -F _ssh ssh

Ponga ese script /etc/bash_completion.d/sshy luego fuente con el siguiente comando:

$ . /etc/bash_completion.d/ssh

Encontré esta guía invaluable y no habría podido escribir esto sin ella. ¡Gracias Steve Kemp por escribir esa excelente guía!

dotancohen
fuente
1
Parece que en Centos 6 entradas en ~ / .ssh / known_hosts anulan las entradas en ~ / .ssh / config, por ejemplo. si tiene foo.bar.baz.com en known_hosts, coincidirá con todo si hace "ssh foo" <tab>; esto no es deseable si tiene un usuario diferente u otras configuraciones que desea aplicar desde ssh confg. Si tiene una entrada en la configuración de ssh que no se completa automáticamente, compruebe si está presente en conocido_hosts y elimínela. Ahora debería funcionar normalmente tomando la configuración de config.
Imran-UK
@ Imran-UK: Se sabe que Ubuntu no hace esa cosa sensata, bajo el pretexto de la seguridad. Aparentemente, la idea es que una entidad maliciosa podría, como usuario, editar ~ / .ssh / config, a pesar de chmod 0600 en el directorio. ¡Hey, no fui yo quien tomó la decisión!
dotancohen
1
Uso zsh & oh-my-zsh, acabo de descubrir que habilitar el complemento "ssh" y poner "HashKnownHosts yes" en mi ~ / .ssh / config parece hacer lo correcto. Puede cambiar el shell sea cual sea la distribución, por lo que podría ser una forma de evitarlo.
Imran-UK
@ Imran-UK: De hecho, he intentado zsh en el pasado y tengo la intención de intentarlo de nuevo. Lo investigaré. Shukran mi amigo!
dotancohen
Sé que llego un poco tarde a la fiesta, pero RHEL 7 completará automáticamente las entradas que estén dentro /etc/hosts, otras distribuciones pueden hacer lo mismo.
Centimane
16

Preenvasado

No dice qué distribución está utilizando, pero en mi sistema Fedora 19 tengo instalado el siguiente paquete, bash-completionque proporciona esta función a través de este archivo de reglas de finalización:

/usr/share/bash-completion/completions/ssh

Aquí está el paquete que he instalado:

$ rpm -aq |grep completion
bash-completion-2.1-2.fc19.noarch

Si observa ese archivo de reglas, verá las estrofas que interrogan al $HOME/.ssh/configarchivo:

$ grep config /usr/share/bash-completion/completions/ssh
    local configfile
    local -a config
        # Search COMP_WORDS for '-F configfile' or '-Fconfigfile' argument
                    configfile="$(dequote "${1:2}")"
                    [[ $1 ]] && configfile="$(dequote "$1")"
        _known_hosts_real -a -F "$configfile" "$cur"
    local configfile
        # Search COMP_WORDS for '-F configfile' argument
                    configfile="$(dequote "${1:2}")"
                    [[ $1 ]] && configfile="$(dequote "$1")"
        _known_hosts_real -a -F "$configfile" "$cur"
    local configfile prefix
        # Search COMP_WORDS for '-F configfile' or '-Fconfigfile' argument
                    configfile="$(dequote "${1:2}")"
                    [[ $1 ]] && configfile="$(dequote "$1")"
                _known_hosts_real -c -a -F "$configfile" "$cur"

Rodando el tuyo

También encontré este Gist, known_hosts_autocomplete.sh , que hace algo similar excepto con el $HOME/.ssh/known_hostsarchivo.

# add to ~/.bash_profile, and close/reopen a shell.  Will autocomplete any
# hosts found in known_hosts.

complete -W "$(echo `cat ~/.ssh/known_hosts | cut -f 1 -d ' ' | \
    sed -e s/,.*//g | uniq | grep -v "\["`;)" ssh

Podría hacer algo similar usando su $HOME/.ssh/configarchivo si por alguna razón no puede encontrar el archivo de regla de finalización para el sshpaquete previamente.

slm
fuente
Gracias. Parece que Ubuntu no viene con /usr/share/bash-completion/completions/ssh. ¿Podría publicar ese archivo completo en algún lugar donde pueda copiarlo? ¡Gracias!
dotancohen
Puede obtener todos los archivos de este archivo: pkgs.fedoraproject.org/repo/pkgs/bash-completion/…
slm
Lamento ser una molestia, ¡pero incluso copiar el archivo ssh de ese archivo tar /usr/share/bash-completion/completions/sshno ayuda! Tampoco ejecuta el complete -W ...comando desde el indicador Bash. ¿Cuál podría ser el problema aquí?
dotancohen
Gracias. Esto parece ser una decisión de diseño conocida en Ubuntu. Por lo tanto, acepto la respuesta a pesar de que no puedo lograr que la finalización de bash funcione para ssho scp.
dotancohen
2
Homebrew para OSX también tiene esto: bash-complete y zsh-completions
Adam Nelson
7

Descubrí que el autocompletado no funcionaba porque Ubuntu hackea hosts conocidos. Puedes añadir

Host *
    HashKnownHosts no

A su .ssh/configarchivo, pero los hosts existentes no se eliminarán.

M1ke
fuente
Gracias. De hecho, ya agregué esta directiva ~/.ssh/configy cambié la directiva /etc/ssh/ssh_config, y eliminé el ~/.ssh/known_hostsarchivo. Después de volver a iniciar sesión en los servidores, los nombres de host todavía se guardan en hash.
dotancohen
He editado mi respuesta; deberá especificar un host y anidar la directiva hash dentro; No enumeré que muchos .ssh/configarchivos ya tendrán esta línea. Avísame si eso funciona.
M1ke
¡Esta es definitivamente la manera fácil de hacerlo! Dado que (las versiones más nuevas de) Ubuntu ahora tienen habilitada la finalización de ssh, esto es probablemente lo que se desea.
John Montgomery
Como agregué a continuación, puede hacer esto, pero probablemente no debería: no es necesario para que la finalización funcione de todos modos. Sin embargo, si no está de acuerdo y solo desea quitar el hash de los hosts existentes después de agregar eso arriba, puede simplemente rm ~ / .ssh / known_hosts, y eso hará que se vuelva a generar (sin hash) siempre que sea necesario. inicia sesión en un nuevo servidor.
Jamieson Becker
3

Para habilitar el autocompletado ssh en Debian y Ubuntu:

sudo apt-get install bash-completion

Tenga en cuenta que esto no tiene nada que ver con el hash conocido_hosts, al contrario de lo que se indicó anteriormente y la pregunta original. Si desea completar automáticamente desde conocido_hosts, entonces, por supuesto, tendría que deshabilitar el hashing, pero eso es muy recomendable.

Por ejemplo, tengo:

Host *
    HashKnownHosts yes

en mi .ssh / config, y todavía tengo la finalización automática de ssh funcionando bien con los hosts enumerados en .ssh / config y / etc / hosts. Es necesario agregar el host a .ssh / config como lo indica el OP:

Host my-awesome-host Nombre de host the.real.host.name

(O bien, puede agregar una entrada de host a / etc / hosts, que es otra fuente para los scripts de Debian / Ubuntu).

Luego, simplemente puede escribir ssh my-awe<tab>y se completará automáticamente. De nuevo, esto es incluso si tienes HashKnownHosts, lo cual es muy recomendable. (Tenga en cuenta que la finalización de bash debe estar habilitada en su shell de bash, y debe tener específicamente esos scripts instalados como se indica arriba para su distribución).

Luego, agregue estas líneas a su .bashrcpara habilitarlo (requiere cerrar sesión y volver a iniciar sesión, o simplemente un nuevo bashtipo para iniciar un nuevo shell. (No necesita habilitarlo si ya está habilitado en /etc/bash.bashrcy /etc/profilefuentes /etc/bash.bashrc).

if [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
fi

Esto permitirá a la terminación automática ssh (entre otras cosas!) De ~/.ssh/config, /etc/hosts, etc.

Tenga en cuenta que Debian por defecto es ash en lugar de bash. Puedes cambiar a bash fácilmente:

sudo usermod -s /bin/bash "$USER"

(Deberá cerrar sesión y volver a iniciarla para que esto surta efecto).

Jamieson Becker
fuente
2

En Ubuntu 14.04, sshcompleta automáticamente los servidores mencionados en su~/.ssh/config

Me di cuenta cuando me di cuenta de que solo uno de los servidores a los que comúnmente accedo se completa automáticamente. La única diferencia entre los dos era una entrada en el archivo de configuración ssh relacionada con la autenticación. Cuando agregué una nueva entrada al archivo de configuración para el otro servidor, también comenzó a completarse automáticamente.

Aquí está la entrada para los que preguntaban:

HOST server-name 
    GSSAPIAuthentication=no

Me sorprendería mucho si importara lo que estaba especificando en la configuración (siempre que siga siendo válido, por supuesto).

Noah
fuente
Gracias Noah, ¿cuál fue esa entrada? En mis sistemas 14.04 y 14.10, el autocompletado no funciona.
dotancohen
No creo que la entrada importe, estoy bastante seguro de que es solo tenerlos allí, pero agregaré la entrada a mi respuesta.
Noah