更新:

更新:

假设我的文件中有以下条目/etc/hosts

192.168.1.10      server1.mydomain.com

SERVER-FILES在当前目录中有一个目录。我想要scp某个目录SERVER-FILES。我键入SE并使用自动完成功能来完成目录名称:

$ scp -rp SE<TAB>

这个完成应该是完全明确的。但是 zsh 自动完成试图变得太聪明,并且对待主机名不区分大小写,因此尝试匹配SE主机名:

$ scp -rp SE<TAB>
SERVER-FILES/
server1.mydomain.com

我如何禁用这个恼人的功能,其中 zsh 尝试匹配不区分大小写的主机名,从而完成SE<TAB> toserver1.mydomain.com` ?

更新:

根据 的建议@zeppelin,我更改了 ssh 完成文件中的以下行Unix/_ssh

- compadd -M 'm:{a-zA-Z}={A-Za-z} r:|.=* r:|=*' "$@" $config_hosts
+ compadd "$@" $config_hosts

但这没有帮助。它完全没有效果。

而且我不明白 的答案@Tomasz Pala。我的 zsh 补全不区分大小写。

请有人告诉我需要改变什么/usr/share/zsh/functions/Completion/Unix/_foo才能改变这种行为。

更新2

我终于缩小了问题范围,并找出了为什么解决方案@Tomasz Pala对他有效,但对我无效:

Unix/_hosts当我在新设置的计算机/用户帐户上更改文件时,该解决方案有效。

scp -r SE<TAB>

上面的命令忽略server1.mydomain.comin /etc/hosts,并且只提供本地目录SERVER-FILES来完成。

但这对我现有的用户帐户不起作用,因为我 server.mydomain.com~/.ssh/config.当我删除该条目时,一切都会按预期进行。

但即使在我目前的情况下,我怎样才能让这个黑客工作~/.ssh/config呢?

答案1

第二个答案试图解释你需要做两件事:

1_ 确保您的一般匹配规则不区分大小写 ( matcher-list) - 从更新的问题来看,它不是,

2_改变Unix/(类型/)_主机(实际位置可能有所不同,但是不是Unix/_ssh- 这个处理~/.ssh/config主机,见下文)最后两行:

_wanted hosts expl host \
   compadd -M 'm:{a-z}={A-Z} r:|.=* r:|=*' -a "$@" - _hosts

所有这些都已经在我的回答中进行了总结,因此只需尝试执行此操作,而无需阅读之前的所有基本原理。另外,由于您的全局配置不区分大小写,@zeppelin 的答案也应该有效,尽管它不使用 $fpath 并且还删除了主机的小->大写字母匹配。

我确实使用更新中的设置对此进行了测试,它按预期工作。

更新:请记住zsh保持其功能的加载,因此修改后_hosts您需要通过重新登录来重新加载它,或者:

unfunction _hosts
autoload -Uz _hosts

另请记住,可以以( ) 的形式zsh“编译”脚本,如果此类文件存在并且比源文件更新,则将使用该文件。zwczcompile [file]

广告。更新2:

处理~/.ssh/config定义的主机实际上与_hosts- 取决于您的zsh版本在任一Unix/(命令/)_ssh或者Unix/(类型/)_ssh_hosts改变

compadd -M 'm:{a-zA-Z}={A-Za-z} r:|.=* r:|=*' "$@" $config_hosts

线路到

compadd -M 'm:{a-z}={A-Z} r:|.=* r:|=*' "$@" $config_hosts

答案2

我相信您正在编辑错误的行。

AFAIK配置主机Unix/_ssh指的是您的主机条目〜./ssh/config, 不是/etc/主机

完成规则为/etc/主机定义得更早一些,在以下块中:

# If users-hosts matches, we shouldn't complete anything else.
if [[ "$IPREFIX" == *@ ]]; then
  _combination -s '[:@]' my-accounts users-hosts "users=${IPREFIX/@}" hosts "$@" && return
else
  _combination -s '[:@]' my-accounts users-hosts \
    ${opt_args[-l]:+"users=${opt_args[-l]:q}"} hosts "$@" && return
fi

但这反过来又重复使用了主机样式定义于Unix/_hosts

所以如果你编辑compad定义在最后Unix/_hosts像这样的文件:

#_wanted hosts expl host \
#    compadd -M 'm:{a-zA-Z}={A-Za-z} r:|.=* r:|=*' -a "$@" - _hosts
_wanted hosts expl host \
     compadd -a "$@" - _hosts

你应该得到你想要的行为。

聚苯乙烯

请注意,编辑系统范围的完成文件通常不是一个很好的做法,因此您可能只想重新定义主机相反,在您的本地 ZSH 配置中,例如通过将类似的函数添加到您的 ~./zsh 中:

_hosts() { compadd $(getent hosts | tr -s ' ' '\t' | cut -f2) }

答案3

这个问题有两个方面。

  1. 不区分大小写的全局 zsh 补全。它很受欢迎,但恕我直言,双向进行是没有意义的。由于我通常不输入大写字母(或错误地输入),因此我们将所有大写字母视为有意输入:

zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'

mkdir DOC drone
ls D[tab] => DOC
ls d[tab] => drone DOC
ls Dr[tab] => [empty]

匹配器列表的问题在于很早就被调用,并且不能根据每个命令/参数进行替换

并且由于匹配器列表重复值被连接起来(引用自文档:“该选项可以多次给出。在这种情况下,给出的所有匹配规范都用空格连接起来,形成要使用的规范字符串"),您以后不能覆盖它,例如

compdef '_hosts -M m:' foo

不会撤销 _hosts 文件中先前的定义。因此,如果您的全局配置中有{a-zA-Z}={A-Za-z},您将无法清除它,即使使用matcher,例如:

zstyle ':completion:*:scp:*:*' matcher "m:{A-Z}={A-Z}"

没有帮助。抱歉,您需要在全球范围内开始解决此问题。权衡解决方案可能是全局两次传递:

zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}' 'm:{A-Z}={a-z}'

ls d[tab] => DOC drone
ls D[tab] => DOC
ls Dr[tab] => drone
  1. 问题的第二部分是函数定义的匹配器列表。如上所述,这是不可清除的,因此您需要通过更改 zsh 提供的文件来处理这个问题,就像 @zeppelin 答案中已经涵盖的那样:

_主机:

[....]
_wanted hosts expl host \
    compadd -M 'm:{a-z}={A-Z} r:|.=* r:|=*' -a "$@" - _hosts

现在,使用系统范围的匹配器列表 'm:{az}={AZ}':

scp d[tab] => /directory/ DOC drone /remote host name/ docker /user/ daemon
scp D[tab] => DOC

所提出的更改原始完成文件的解决方案不是正确的方法,就像@zeppelin 指出的那样......但创建自己的主机获取功能也有缺陷。不幸的是,正确的解决方案取决于 zsh 开发人员,他们可能会添加匹配器清除选项、定义一些新样式或简单地修复完成函数以不忽略大小写,只需遵循全局设置即可。

然而,即使存在这个问题,也有一个很好且干净的解决方案 - 而不是修改(可能提供了一些发行版包) /usr/share/zsh/... 人们可以将固定副本放在 /etc/zsh/functions 中,然后简单地告诉 zsh使用此位置:fpath=(/etc/zsh/functions $fpath).这样可以避免系统更新后覆盖文件。

总结

  1. 更改您的全局匹配器列表:

zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}' 'm:{A-Z}={a-z}'

  1. 将修改后的 _hosts 文件放在某个 /etc/zsh 或 $HOME 位置:

fpath=(/etc/zsh/functions $fpath)

/etc/zsh/functions/_hosts:

[....]
_wanted hosts expl host \
    compadd -M 'm:{a-z}={A-Z} r:|.=* r:|=*' -a "$@" - _hosts

答案4

您无需更改任何完成功能即可获得所需的内容。只需将其添加到您的~/.zshrc文件中:

# $PREFIX is the part of the current word that's to the left of the cursor.
# $SUFFIX is the part of the current word that's to the right of the cursor.
# Let's ignore all host completions that don't explicitly match what we've typed, 
# but allow for additional characters at the cursor position and at the end of what 
# we've typed. This makes the matching case sensitive.
# `(b)` escapes characters that are significant to globbing.
zstyle -e ':completion:*:hosts' ignored-patterns 'reply=(
  "^(${(b)PREFIX}*${(b)SUFFIX}*)"
)'

# But if that would lead to no results, then offer the ignored completions anyway.
zstyle ':completion:*' completer _expand _complete _ignored

我已经使用您发布的配置和测试用例对此进行了测试,并且它有效。

文档:

相关内容