Bagaimana cara mengedit perintah selesai untuk ssh di zsh?

11

Saya ingin mengatur penyelesaian perintah pada zsh untuk menampilkan nama host setelah saya mengetik

ssh [TAB]

mengeluarkan nama dari file .ssh / config saya (dan lebih disukai dari known_hosts dan / etc / hosts dan tempat lain yang masuk akal) dan menyajikan satu daftar tunggal.

Itu beberapa dari ini saat ini, tetapi

  1. tidak menggunakan .ssh / config sama sekali
  2. itu membutuhkan nama pengguna terlebih dahulu, meskipun menggunakan .ssh / config membuat pengetikan nama pengguna tidak perlu
  3. ini menyajikan banyak daftar (mungkin satu dari known_hosts dan lainnya dari / etc / hosts, tapi saya belum memverifikasi itu)

Jadi saya ingin memasukkan nama pengguna yang dikenal serta nama host yang dikenal dalam daftar (lebih disukai tunggal) setelah mengetik ssh [TAB]

(Saya datang ke sini sebelum Google karena 1) itu akan menghasilkan jawaban yang disimpan di sini, dan 2) mungkin lebih efisien. Jika tidak ada orang lain yang menjawab, saya akan mencari jawabannya.)

iconoclast
sumber
Ini akan menjadi pertanyaan untuk pengguna super, saya pikir
Etienne Perot
Sebenarnya, melihatnya sekarang saya seharusnya bertanya di unix.stackexchange.com. (Tapi saya tidak ingat apakah itu sekitar 2 tahun yang lalu ketika saya memintanya.) Adakah yang ingin memigrasikannya?
iconoclast

Jawaban:

16

Inilah bagian yang relevan dari saya .zshrc. Itu belum berubah sejak tahun 2002, jadi saya mungkin menulisnya secara berbeda hari ini, tetapi masih berfungsi untuk melengkapi nama host dari ~/.ssh/configdan ~/.ssh/known_hosts(jika HashKnownHoststidak aktif - itu tidak ada pada masa itu).

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 'SANGAT berhenti menjadi jahat'
sumber
Oke, saya akhirnya tahu mengapa ini tidak berhasil. Masalahnya bukan dengan kode yang Anda berikan: itu berfungsi dengan baik, setelah masalah lain diselesaikan.
iconoclast
1

Fungsi yang menyediakan sshpenyelesaian terletak di /usr/share/zsh/functions/Completion/Unix/_sshpada sistem saya.

Lihat juga man zshcompsysdokumentasi (terutama lakukan pencarian pada "host" yang muncul di banyak tempat dan "ssh" yang muncul di beberapa tempat).

Mungkin saja menambahkan zstyleperintah pada Anda ~/.zshrcakan melakukan apa yang Anda cari tanpa harus memodifikasi fungsi penyelesaian.

Dijeda sampai pemberitahuan lebih lanjut.
sumber
Atau di /usr/share/zsh/4.3.9/functions/_sshdalam Mac OS X (sesuaikan versi)
Studer
Saya sumber file itu, dan ketik ssh <TAB> dan saya mendapatkan penyelesaian nama file. Ada apa dengan itu?
iconoclast
1

Saya melakukan ini menggunakan daftar semua host di domain yang diberikan menggunakan dig. Anda dapat mengganti fungsi di bawah ini dengan sistem pencarian apa pun yang Anda inginkan termasuk file host Anda atau daftar statis:

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

Catatan: Kode di atas mungkin tidak sepenuhnya menggantikan sistem lengkap untuk perintah ssh di konfigurasi Anda. Jika Anda memiliki masalah dengannya, cobalah mengubah perintah "ssh" menjadi beberapa perintah acak lainnya seperti "mycompletetest" dan lihat apakah penyelesaiannya berhasil.

Perhatikan juga bahwa ini melakukan transfer zona dns pada setiap penyelesaian! Jika Anda sering menggunakan ini atau pada domain yang cukup statis akan masuk akal untuk melakukan pencarian dan menyimpan hasilnya, maka dalam fungsi pencarian Anda cukup atur reply = zone_result.

Caleb
sumber
Saya tidak bisa membuatnya bekerja sama sekali. Jelas saya harus mengubah bagian balasan, tetapi dapatkah Anda memberikan contoh yang berfungsi dengan teks statis, jadi saya tahu format apa yang seharusnya? (Saya mencoba apa yang saya mengerti halaman manual untuk mengatakan, dan mengoreksi -k ke -K, dan itu masih tidak berhasil.)
iconoclast
Format balasannya cukup sederhana, hanya gumpalan teks lurus, satu jawaban yang mungkin per baris. Hal dns mungkin bagian yang sulit. Server DNS Anda harus mendukung transfer zona agar ini berfungsi. Ini biasanya berarti Anda harus berbicara dengan server dns primer untuk domain yang dimaksud, seperti ini dig axfr mydomain.com @ns1.mydomain.com. Pastikan Anda dapat menjalankannya secara manual dan bagian dari output harus berupa daftar host yang terdaftar di domain itu dan A atau catatan apa pun mereka. Itulah yang saya cari, kemudian memotong hanya bagian hostname bukan catatan yang sepenuhnya memenuhi syarat.
Caleb
Harap dicatat bahwa saya telah menulis ulang kode contoh dalam jawaban saya agar solusi cut and paste berfungsi penuh termasuk nama domain tempat pencarian transfer zona berfungsi. Anda kemudian dapat menyesuaikan ke suite. Saya meminta maaf untuk dokumen asli yang berakhir dengan dua kesalahan ketik sejak saya merobek sekitar 20 lapisan tambahan barang yang ada di file .zshrc saya yang tidak relevan dengan contoh ini.
Caleb
Perintah dig di backticks berfungsi sekarang (terima kasih telah mengeditnya!), Tapi itu tidak menunjukkan hasil perintah itu ketika saya mengetik ssh <TAB>. Apakah ada hal lain di luar ini yang perlu diaktifkan sebelum akan berfungsi?
iconoclast
0

Saya suka menyimpan known_hostsfile hash saya dan lebih suka tidak HashKnownHostsmematikan. Saya menemukan bahwa menyemai apa yang dimiliki @Gilles dengan apa yang sudah ada dalam sejarah saya telah cukup efektif untuk kebutuhan saya.

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

Juga, FWIW, inilah yang saya gunakan untuk 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
sumber