Як відредагувати завершення команди для ssh на zsh?


11

Я хотів би встановити завершення команди на zsh для відображення імен хостів після введення

ssh [TAB]

вилучення імен з мого .ssh / config-файлу (а краще з відомих_хостів та / і т.д. / хостів та будь-якого іншого місця, яке має сенс) та подання одного єдиного списку.

Дещо з цього робить і зараз, але

  1. він взагалі не використовує .ssh / config
  2. спочатку потрібне ім'я користувача, навіть якщо використання .ssh / config робить введення імен користувачів непотрібними
  3. він містить декілька списків (можливо, один із відомих_хостів та інший від / etc / hosts, але я цього не підтвердив)

Тому я хочу включати відомі імена користувачів, а також відомі імена хостів у (бажано, єдиний) список після введення ssh [TAB]

(Я заходжу сюди перед Google, тому що 1) це призведе до того, що відповідь зберігається тут, і 2) це, мабуть, більш ефективно. Якщо ніхто більше не відповість, я знайду відповідь.)


Це було б питання до суперпользователя, я думаю
Етьєн Перо

Власне, дивлячись на це зараз, я мав би запитати його на unix.stackexchange.com. (Але я не пам'ятаю, чи було це близько 2 років тому, коли я запитав це.) Хтось хоче перенести це?
іконоборство

Відповіді:


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

Гаразд, я нарешті зрозумів, чому це не працює. Проблема була не з наданим вами кодом: він працює добре, як тільки інша проблема була вирішена.
іконоборство

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> і я отримаю завершення імені файлу. Що з цим?
іконоборство

1

Я роблю це, використовуючи список усіх хостів на даному домені за допомогою dig. Ви можете замінити функцію нижче будь-якою системою пошуку, включаючи файл хостів або статичний список:

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

Формат відповіді досить простий, це просто прямий текст, одна можлива відповідь на рядок. Річ у dns - це, мабуть, хитра частина. Ваш сервер DNS повинен підтримувати передачу зон, щоб це працювало. Зазвичай це означає, що вам потрібно спілкуватися з основним сервером dns для домену, про який йдеться, як це dig axfr mydomain.com @ns1.mydomain.com. Переконайтеся, що ви можете запустити це вручну, і частина виводу повинна бути списком хостів, зареєстрованих у цьому домені, та їх A або будь-яких записів. Це те, за що я вітався, а потім вирізав лише частину імені хоста, а не повністю кваліфікований запис.
Калеб

Будь ласка, зауважте, що я переписав приклад коду у своїй відповіді, щоб бути повністю працюючим вирізати та вставити рішення, включаючи доменне ім'я, для якого працює пошук передачі зони. Потім ви можете підлаштувати їх під номер. Я прошу вибачення за оригінал, який закінчився двома друкарськими помилками, коли я видобув приблизно 20 зайвих шарів речей, які були у моєму файлі .zshrc, що не стосується цього прикладу.
Калеб

Команда dig у задніх редакціях працює зараз (спасибі за її редагування!), Але вона не показує жодного з результатів цієї команди, коли я ввожу ssh <TAB>. Чи є ще щось поза цим, що потрібно активувати, перш ніж воно запрацює?
іконоборство

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.