Wie bearbeite ich die Befehlsvervollständigung für ssh auf zsh?

11

Ich möchte die Befehlsvervollständigung auf zsh einrichten, um Hostnamen nach der Eingabe anzuzeigen

ssh [TAB]

Nehmen Sie die Namen aus meiner .ssh / config-Datei (und vorzugsweise aus bekannten_Hosts und / etc / hosts und an jedem anderen Ort, der Sinn macht) und präsentieren Sie eine einzige Liste.

Es macht derzeit einiges davon, aber

  1. Es wird überhaupt keine .ssh / config verwendet
  2. Es erfordert zuerst einen Benutzernamen, obwohl die Verwendung von .ssh / config die Eingabe von Benutzernamen unnötig macht
  3. Es werden mehrere Listen angezeigt (wahrscheinlich eine von bekannten_Hosts und eine andere von / etc / hosts, aber das habe ich nicht überprüft.)

Daher möchte ich bekannte Benutzernamen sowie bekannte Hostnamen in die (vorzugsweise einzelne) Liste aufnehmen, nachdem ich ssh [TAB] eingegeben habe.

(Ich komme vor Google hierher, weil 1) die Antwort hier gespeichert wird und 2) sie wahrscheinlich effizienter ist. Wenn sonst niemand antwortet, werde ich die Antwort suchen.)

Bilderstürmer
quelle
Dies wäre eine Frage für Superuser, denke ich
Etienne Perot
Eigentlich hätte ich es mir jetzt auf unix.stackexchange.com fragen sollen. (Aber ich erinnere mich nicht, ob das vor ungefähr 2 Jahren war, als ich es gefragt habe.) Möchte jemand es migrieren?
Bilderstürmer

Antworten:

16

Hier ist der relevante Teil von mir .zshrc. Es hat sich seit 2002 nicht geändert, daher könnte ich es heute anders schreiben, aber es funktioniert immer noch, um Hostnamen von ~/.ssh/configund zu vervollständigen ~/.ssh/known_hosts(falls HashKnownHostsdeaktiviert - es gab es damals nicht).

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 - hör auf böse zu sein'
quelle
Okay, ich habe endlich herausgefunden, warum das nicht funktioniert. Das Problem lag nicht an dem von Ihnen bereitgestellten Code: Es funktioniert einwandfrei, sobald das andere Problem behoben wurde.
Bilderstürmer
1

Die Funktion, die die sshVervollständigung bereitstellt, befindet sich /usr/share/zsh/functions/Completion/Unix/_sshauf meinem System unter.

Weitere Informationen finden Sie auch man zshcompsysin der Dokumentation (insbesondere suchen Sie nach "Host", das an mehreren Stellen angezeigt wird, und nach "ssh", das an mehreren Stellen angezeigt wird).

Es ist möglich, dass das Hinzufügen eines zstyleBefehls zu Ihrem Befehl ~/.zshrcdas tut, wonach Sie suchen, ohne die Abschlussfunktion ändern zu müssen.

Bis auf weiteres angehalten.
quelle
Oder in /usr/share/zsh/4.3.9/functions/_sshMac OS X (Version anpassen)
Studer
Ich beziehe diese Datei, gebe ssh <TAB> ein und erhalte die Vervollständigung des Dateinamens. Was ist damit los?
Bilderstürmer
1

Ich mache dies mit einer Liste aller Hosts auf einer bestimmten Domain mit dig. Sie können die folgende Funktion durch ein beliebiges Suchsystem ersetzen, einschließlich Ihrer Hosts-Datei oder einer statischen Liste:

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

Hinweis: Der obige Code ersetzt möglicherweise nicht das gesamte System für den Befehl ssh in Ihrer Konfiguration. Wenn Sie Probleme damit haben, versuchen Sie, den Befehl "ssh" in einen anderen zufälligen Befehl wie "mycompletetest" zu ändern, und prüfen Sie, ob die Vervollständigung dafür funktioniert.

Beachten Sie auch, dass dies die DNS-Zonenübertragung bei jedem Abschluss durchführt! Wenn Sie dies häufig oder in einer ziemlich statischen Domäne verwenden, ist es sinnvoll, die Suche durchzuführen und das Ergebnis zu speichern. Setzen Sie dann in Ihrer Suchfunktion einfach reply = zone_result.

Caleb
quelle
Ich kann das überhaupt nicht zum Laufen bringen. Natürlich muss ich den Antwortteil ändern, aber können Sie ein funktionierendes Beispiel mit statischem Text geben, damit ich weiß, in welchem ​​Format es sein sollte? (Ich habe versucht, was ich auf der Manpage verstanden habe, und -k auf -K korrigiert, und es hat immer noch nicht funktioniert.)
Bilderstürmer
Das Antwortformat ist ziemlich einfach, es ist nur ein gerader Text-Blob, eine mögliche Antwort pro Zeile. Das DNS-Ding ist wahrscheinlich der schwierige Teil. Ihr DNS-Server muss die Zonenübertragung unterstützen, damit dies funktioniert. Dies bedeutet normalerweise, dass Sie mit dem primären DNS-Server für die betreffende Domäne wie folgt sprechen müssen dig axfr mydomain.com @ns1.mydomain.com. Stellen Sie sicher, dass Sie dies manuell ausführen können und ein Teil der Ausgabe eine Liste der in dieser Domäne registrierten Hosts und ihrer A- oder beliebigen Datensätze sein sollte. Das war es, wonach ich gesucht habe und dann nur den Hostnamen-Teil abgeschnitten habe, nicht den vollständig qualifizierten Datensatz.
Caleb
Bitte beachten Sie, dass ich den Beispielcode in meiner Antwort umgeschrieben habe, um eine voll funktionsfähige Lösung zum Ausschneiden und Einfügen zu erhalten, einschließlich eines Domainnamens, für den die Suche nach Zonentransfers funktioniert. Sie können dann auf die Suite zuschneiden. Ich entschuldige mich für das Original, das mit zwei Tippfehlern endete, als ich ungefähr 20 zusätzliche Ebenen von Dingen herausgerissen habe, die in meiner .zshrc-Datei enthalten waren und für dieses Beispiel nicht relevant sind.
Caleb
Der dig-Befehl in Backticks funktioniert jetzt (danke für die Bearbeitung!), Zeigt jedoch keine Ergebnisse dieses Befehls an, wenn ich ssh <TAB> eingebe. Gibt es noch etwas anderes, das aktiviert werden muss, bevor es funktioniert?
Bilderstürmer
0

Ich mag es, meine Hash- known_hostsDatei zu behalten und möchte sie lieber nicht HashKnownHostsausschalten. Ich hatte festgestellt, dass das Aussäen von @Gilles mit dem, was bereits in meiner Geschichte enthalten ist, für meine Bedürfnisse sehr effektiv war.

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

Außerdem, FWIW, habe ich Folgendes für Bash verwendet:

# 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
quelle