zshでsshのコマンド補完を編集する方法は?


11

入力後にホスト名を表示するためにzshでコマンド補完を設定したい

ssh [TAB]

私の.ssh / configファイルから(できればknown_hostsと/ etc / hosts、そして理にかなっている他の場所から)名前を取り出し、1つのリストを表示します。

現在これの一部を実行していますが、

  1. .ssh / configをまったく使用しません
  2. .ssh / configを使用するとユーザー名の入力が不要になりますが、最初にユーザー名が必要です
  3. 複数のリストを表示します(おそらく、1つはknown_hostsから、もう1つは/ etc / hostsからですが、確認していません)

ssh [TAB]と入力した後、既知のユーザー名と既知のホスト名を(できれば単一の)リストに含めたい

(Googleの前にここに来るのは、1)回答がここに保存されることになるからです。2)おそらくより効率的です。誰も答えない場合は、答えを探します。)


これはスーパーユーザーにとっての質問だと思う
エティエンヌペロー

実際、今見てみると、unix.stackexchange.comで質問する必要がありました。(しかし、私がそれを尋ねたとき、それが約2年前だったかどうかは思い出せません。)誰もがそれを移行したいですか?
iconoclast

回答:


16

ここに私の関連する部分があります.zshrc。今日は違っそれを書くかもしれないので、それは、2002年以来変わっていないが、それはまだからの完全なホスト名に働く~/.ssh/config~/.ssh/known_hosts(あればHashKnownHostsオフになっている-それは当時存在していませんでした)。

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

さて、私はついにこれが機能しなかった理由を見つけました。問題はあなたが提供したコードにはありませんでした。他の問題が解決されると、問題なく動作します。
iconoclast

1

ssh補完を提供する機能は/usr/share/zsh/functions/Completion/Unix/_ssh私のシステムにあります。

またman zshcompsys、ドキュメントも参照してください(特に、複数の場所に表示される「ホスト」と、いくつかの場所に表示される「ssh」で検索してください)。

zstyleコマンドを追加~/.zshrcすると、補完機能を変更することなく、探していることを実行できる可能性があります。


または/usr/share/zsh/4.3.9/functions/_sshMac OS Xで(バージョンを適応)
Studer

そのファイルを入手し、「ssh <TAB>」と入力すると、ファイル名が補完されます。どうした?
iconoclast

1

これを行うには、digを使用して特定のドメイン上のすべてのホストのリストを使用します。以下の関数を、hostsファイルまたは静的リストを含む任意のルックアップシステムに置き換えることができます。

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

注:上記のコードは、構成内のsshコマンドのシステム全体を完全に置き換えるとは限りません。問題がある場合は、「ssh」コマンドを「mycompletetest」のような他のランダムコマンドに変更してみて、補完が機能するかどうかを確認してください。

また、これは完了ごとにDNSゾーン転送を行うことに注意してください!これを頻繁にまたはかなり静的なドメインで使用する場合、検索を実行して結果を保存するのが理にかなっています。検索関数でreply = zone_resultを設定するだけです。


私はそれをまったく機能させることができません。当然、返信部分を変更する必要がありますが、静的テキストを使用した実例を示すことができますので、どの形式にする必要があるかを知っていますか?(私は言うためにマニュアルページを理解し、-kを-Kに修正しましたが、それでも動作しませんでした。)
iconoclast

返信の形式は非常にシンプルで、1行に1つの回答が可能なストレートテキストBLOBにすぎません。DNSのことはおそらく注意が必要な部分です。DNSサーバーは、これが機能するためにゾーン転送をサポートする必要があります。これは通常、次のように、問題のドメインのプライマリDNSサーバーと通信する必要があることを意味しますdig axfr mydomain.com @ns1.mydomain.com。手動で実行できることを確認してください。出力の一部は、そのドメインに登録されているホストとそのAまたは任意のレコードのリストである必要があります。それが私が欲しがっていたので、完全修飾されたレコードではなく、ホスト名の部分のみを切り捨てました。
カレブ

回答のサンプルコードを、ゾーン転送ルックアップが機能するドメイン名を含む完全に機能するカットアンドペーストソリューションに書き直したことに注意してください。その後、スイートに合わせて調整できます。私は、この例に関係のない.zshrcファイルにあった約20の余分なレイヤーをリッピングしたときから2つのタイプミスで終わったオリジナルをおappびします。
カレブ

backticksのdigコマンドは機能します(編集してくれてありがとう!)が、ssh <TAB>と入力してもそのコマンドの結果は表示されません。これ以外にも、機能する前に有効にする必要があるものがありますか?
iconoclast

0

私はハッシュ化されたknown_hostsファイルを保持するのが好きで、むしろHashKnownHosts消したくない。私は、@ Gillesがすでに私の歴史にあるものをシードすることは、私のニーズにとって非常に効果的であることがわかりました。

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

また、FWIW、これは私が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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.