我想在 zsh 上设置命令完成,以便在输入后显示主机名
ssh [TAB]
从我的 .ssh/config 文件中取出名称(最好是从 known_hosts 和 /etc/hosts 以及其他有意义的地方取出)并提供一个列表。
目前它已经实现了部分功能,但是
- 它根本不使用 .ssh/config
- 它首先需要输入用户名,尽管使用 .ssh/config 就不需要输入用户名了
- 它提供了多个列表(可能一个来自known_hosts,另一个来自/etc/hosts,但我还没有验证)
因此,我希望在输入 ssh [TAB] 后在(最好是单个)列表中包含已知用户名以及已知主机名
(我先来这里,然后才使用 Google,因为 1)这样答案就会存储在这里,2)这样可能效率更高。如果没有其他人回答,我会寻找答案。)
答案1
以下是我的 的相关部分.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
答案2
提供完成的功能ssh
位于/usr/share/zsh/functions/Completion/Unix/_ssh
我的系统上。
另请参阅man zshcompsys
文档(特别是搜索在多个地方出现的“host”和在几个地方出现的“ssh”)。
可能只需添加一个zstyle
命令就~/.zshrc
可以完成您想要的操作,而无需修改完成功能。
答案3
我使用 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。
答案4
我喜欢保留我的哈希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