Come modificare il completamento del comando per ssh su zsh?


11

Vorrei impostare il completamento del comando su zsh per visualizzare i nomi host dopo aver digitato

ssh [TAB]

prendendo i nomi dal mio file .ssh / config (e preferibilmente da known_hosts e / etc / hosts e da qualsiasi altra parte che abbia senso) e presentando un unico elenco.

Fa un po 'di questo attualmente, ma

  1. non usa affatto .ssh / config
  2. richiede prima un nome utente, anche se l'uso di .ssh / config rende superflua la digitazione dei nomi utente
  3. presenta più elenchi (probabilmente uno da known_hosts e un altro da / etc / hosts, ma non l'ho verificato)

Quindi voglio includere nomi utente noti e nomi host noti nell'elenco (preferibilmente singolo) dopo aver digitato ssh [TAB]

(Vengo qui prima di Google perché 1) comporterà la memorizzazione della risposta qui e 2) probabilmente è più efficiente. Se nessun altro risponde, cercherò la risposta.)


Questa sarebbe una domanda per il superutente, penso
Etienne Perot,

In realtà, guardandolo ora avrei dovuto chiederlo su unix.stackexchange.com. (Ma non ricordo se è stato circa 2 anni fa quando l'ho chiesto.) Qualcuno vuole migrarlo?
iconoclasta

Risposte:


16

Ecco la parte rilevante della mia .zshrc. Non è cambiato dal 2002, quindi potrei scriverlo diversamente oggi, ma funziona ancora per completare i nomi host da ~/.ssh/confige ~/.ssh/known_hosts(se HashKnownHostsè spento - non esisteva in quei giorni).

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

Ok, ho finalmente capito perché non funzionava. Il problema non era con il codice fornito: funziona benissimo, una volta risolto l'altro problema.
iconoclasta il

1

La funzione che fornisce il sshcompletamento si trova in /usr/share/zsh/functions/Completion/Unix/_sshsul mio sistema.

Consulta anche la man zshcompsysdocumentazione (in particolare esegui una ricerca su "host" che appare in più punti e "ssh" che appare in un paio di punti).

Potrebbe essere possibile che l'aggiunta di un zstylecomando al tuo ~/.zshrcfaccia quello che stai cercando senza dover modificare la funzione di completamento.


O su /usr/share/zsh/4.3.9/functions/_sshin Mac OS X (adattare la versione)
Studer

Prendo il file e digito ssh <TAB> e ottengo il completamento del nome file. Che succede?
iconoclasta,

1

Lo faccio usando un elenco di tutti gli host su un determinato dominio usando dig. È possibile sostituire la funzione seguente con qualsiasi sistema di ricerca desiderato, incluso il file hosts o un elenco statico:

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: il codice sopra potrebbe non sostituire completamente il sistema completo per il comando ssh nella configurazione. Se hai problemi con esso, prova a cambiare il comando "ssh" in qualche altro comando casuale come "mycompletetest" e vedi se il completamento funziona per quello.

Nota anche che questo fa il trasferimento della zona DNS ad ogni completamento! Se lo usi molto o su un dominio abbastanza statico, sarebbe logico fare la ricerca e salvare il risultato, quindi nella tua funzione di ricerca basta impostare reply = zone_result.


Non riesco a farlo funzionare affatto. Ovviamente devo cambiare la parte di risposta, ma puoi dare un esempio funzionante con testo statico, quindi so in che formato dovrebbe essere? (Ho provato quello che ho capito nella pagina man e ho corretto -k to -K, e ancora non ha funzionato.)
iconoclasta

Il formato di risposta è piuttosto semplice, è solo un blob di testo semplice, una possibile risposta per riga. La cosa del DNS è probabilmente la parte difficile. Il tuo server DNS deve supportare il trasferimento di zona affinché funzioni. Questo di solito significa che devi parlare con il server DNS primario per il dominio in questione, in questo modo dig axfr mydomain.com @ns1.mydomain.com. Assicurati di poterlo eseguire manualmente e parte dell'output dovrebbe essere un elenco di host registrati su quel dominio e i loro record A o qualunque. Questo è ciò che cercavo, quindi tagliare solo la parte del nome host e non il record completo.
Caleb,

Si prega di notare che ho riscritto il codice di esempio nella mia risposta per essere completamente funzionante soluzione taglia e incolla incluso un nome di dominio per cui la ricerca del trasferimento di zona funziona. È quindi possibile personalizzare la suite. Mi scuso per l'originale che è finito con due errori di battitura da quando ho strappato circa 20 strati extra di cose che erano nel mio file .zshrc che non sono rilevanti per questo esempio.
Caleb,

Il comando dig nei backtick ora funziona (grazie per averlo modificato!), Ma non mostra nessuno dei risultati di quel comando quando digito ssh <TAB>. C'è qualcos'altro al di fuori di questo che deve essere abilitato prima che funzioni?
iconoclasta

0

Mi piace conservare il mio known_hostsfile con hash e preferirei non HashKnownHostsdisattivarlo. Avevo scoperto che seminare ciò che @Gilles ha con ciò che è già nella mia storia è stato abbastanza efficace per le mie esigenze.

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

Inoltre, FWIW, questo è quello che ho usato per 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.