Как отредактировать завершение команды для ssh на zsh?

11

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

ssh [TAB]

вынуть имена из моего файла .ssh / config (и желательно из известных_хостов и / etc / hosts и в любом другом месте, которое имеет смысл) и представить один список.

Это делает кое-что из этого в настоящее время, но

  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документацию (особенно выполните поиск по «host», который появляется в нескольких местах, и «ssh», который появляется в нескольких местах).

Вполне возможно, что добавление zstyleкоманды к вашему ~/.zshrcбудет делать то, что вы ищете, без необходимости изменять функцию завершения.

Приостановлено до дальнейшего уведомления.
источник
Или в /usr/share/zsh/4.3.9/functions/_sshMac OS X (адаптируйте версию)
Studer
Я получаю этот файл и набираю ssh <TAB> и получаю завершение имени файла. Что с этим?
иконоборчество
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
Формат ответа довольно прост, это просто текстовый шарик, один возможный ответ на строку. DNS вещь, вероятно, самая сложная часть. Ваш DNS-сервер должен поддерживать передачу зоны, чтобы это работало. Обычно это означает, что вы должны общаться с основным DNS-сервером для рассматриваемого домена, как этот dig axfr mydomain.com @ns1.mydomain.com. Убедитесь, что вы можете запустить это вручную, и часть вывода должна быть списком хостов, зарегистрированных в этом домене, и их A или любых других записей. Это то, к чему я стремился, а затем отрезал только часть имени хоста, а не полную запись.
Калеб
Обратите внимание, что я переписал пример кода в своем ответе, чтобы он был полностью рабочим решением для вырезки и вставки, включая доменное имя, для которого работает поиск передачи зоны. Затем вы можете адаптировать к сюиту. Я прошу прощения за оригинал, который закончился двумя опечатками, когда я вырвал около 20 дополнительных слоев материала, который был в моем файле .zshrc, который не имеет отношения к этому примеру.
Калеб
Команда dig в backticks теперь работает (спасибо за редактирование!), Но она не показывает никаких результатов этой команды, когда я набираю 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
Карл Уилбур
источник