如何在zsh上编辑ssh的命令完成?


11

我想在zsh上设置命令完成功能以在键入后显示主机名

ssh [TAB]

将名称从我的.ssh / config文件中删除(最好是从known_hosts和/ etc / hosts以及其他有意义的地方),并提供一个列表。

它目前正在执行某些操作,但是

  1. 它根本不使用.ssh / config
  2. 即使使用.ssh / config,也无需输入用户名,但它首先需要用户名
  3. 它显示了多个列表(可能一个来自known_hosts,另一个来自/ etc / hosts,但我尚未验证)

因此,我想在输入ssh [TAB]后在(最好是单个)列表中包括已知的用户名和已知的主机名。

(我来Google之前是因为1)它将导致答案存储在此处,以及2)可能更有效。如果没有其他人回答,我将寻找答案。)


我认为这将是超级用户的问题
Etienne Perot

实际上,现在来看它,我应该在unix.stackexchange.com上询问它。(但是我不记得那是大约两年前问到的。)有人要迁移它吗?
iconoclast 2012年

Answers:


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 2010年

我找到该文件,然后输入ssh <TAB>,并得到文件名补全。怎么了
iconoclast

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或任何记录的列表。这就是我想要的,然后只删除主机名部分而不是完全限定的记录。
Caleb 2010年

请注意,我已将答案中的示例代码重写为完全有效的剪切和粘贴解决方案,其中包括适用于区域传输查找的域名。然后,您可以定制套件。我为原始版本表示歉意,因为当我删除.zshrc文件中与该示例无关的20层额外内容时,最终出现两次错别字。
Caleb

反引号中的dig命令现在可以使用(感谢对其进行编辑!),但是当我键入ssh <TAB>时,它不显示该命令的任何结果。除此以外,还有其他需要启用的功能吗?
iconoclast 2010年

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.