我有一台带有大量 USB 硬盘的业余爱好服务器。我启用了积极的电源管理和较短的旋转超时,因为这些驱动器基本上是冷存储,可以在需要时快速访问。因此,它们中的大多数将 99.9% 的时间花在 APM 待机状态,直到我需要访问它们,此时它们就会启动,对于单个驱动器,我可以在 10 秒内访问,对于 RAID 中的驱动器,最多 30 秒。
ZSH 补全系统在这方面让我头疼,因为它提供的可以说是非常棒的自动补全功能也会进行某种自动路径验证,即使我不按 TAB 键,即使我使用箭头用于遍历 shell 命令历史记录的键。
例如,我可以输入rsync
,然后按向上键开始遍历之前rsync
命令的历史记录,然后完成魔术立即开始访问这些命令中的文件系统路径以验证并对它们执行魔术操作。这不仅会导致 zsh 阻塞并变得无响应的巨大暂停,还会使休眠驱动器旋转,从而增加这些旋转器的磨损。由于其网络性质,任何网络安装路径也会导致延迟。
在编写路径时它也会起作用,我只需输入字母、斜杠和通配符。
我发现了很多类似抱怨的问题,像这个,但我还没有找到可以精确解决这个问题的东西。
在上面提到的帖子中,有一个指向 zsh Completion System 文档的链接,在阅读它们时我发现自己仍然感到困惑。从文档中我什至不确定语法是什么zstyle
,而且我对很多术语感到困惑。
基本上我只是在寻找一种方式对 zsh 说:“听着,伙计,我喜欢你正在做的事情,但是你能用你所有的魔法等待我按下 TAB 键吗?”
答案1
除非您在“正常”配置中按 Tab 键,否则 Zsh 不会开始执行任何类型的完成魔法。这是可以做到的,但需要一些认真的延期。
如果您使用 zsh 配置框架,它可能会标配该功能。您必须查找该框架的文档才能了解如何禁用它,而不是 zsh 本身的文档。
根据您对此功能的描述,行编辑器一定是以某种方式定制的。我不确定您是否可以在某个地方定义一个钩子来实现此行为,或者是否必须覆盖自插入。尝试列出关键竞价bindkey
,看看是否有什么突出的地方。也许与您得到的结果进行比较zsh -f
(这会启动 zsh 而不读取.zshrc
其他配置文件)。
如果您对发生的情况感到困惑,可以告诉它将运行的所有命令记录到文件中。 (set -x
终端上有一个简单的日志,但可能太多而无法实际使用。)
exec 2>zsh.log; set -x
撤销:
set +x; exec 2>/dev/tty
如果您想跟踪完成过程(而不是在未完成场景中触发完成之类的过程),您可以运行以下命令_complete_debug
(^X?
默认情况下绑定)而不是按Tab。
zsh 文档很难阅读。我建议查找与您想要做的事情接近的示例,然后在找到您可能需要的命令/变量/函数/...后查看文档。这zstyle
文档解释了它的工作原理,但要了解它在完成系统中的使用方式,您需要了解补全使用的 zstyle 上下文的语法,然后要知道它在哪里使用,您需要查找使用它的函数的文档,或者有时阅读源代码。无论如何,您不需要了解有关 zstyle 的任何内容来解决您的问题:仅通过完成配置无法触发完成之外的自动行为(并且可能根本不会,尽管该自动行为可能会模仿完成并重用其设置) 。必须对行编辑器进行一些配置,可能是一堆自定义键绑定。
答案2
(警告:只有当您喜欢故事时间并且对我如何调试并找到罪魁祸首感兴趣时才阅读本文。有些人不能很好地处理冗长的内容 - 如果那是您,那么这不适合您)。
好的,所以我将其添加为“答案”,而不是更新原始问题,因为我将记录我如何找出罪魁祸首。实际问题的真正答案(“谁导致我的(哦我的)zsh 滞后”是吉尔斯上面的答案,这只是他的提示的附录,我认为这对其他人调试“哦我的 ZSH 可能有用” 。”把你喜欢的放在那里(请不要不喜欢这个)。
以下是我遇到的几个具体问题,我用它们来测试我对配置所做的更改:
- 我在位于已停止旋转的驱动器上的文件夹路径中有一个打开的会话,例如
/media/drive-f/Apps
.我离开此会话的时间已经足够长,驱动器已经停止旋转,但 zsh 会话仍然处于该路径。我想返回我的主文件夹,所以我开始输入cd
.我一点击c
, zsh 就会阻塞,驱动器就会旋转。有些东西想要检查当前目录,作为对我在键盘上打字的反应。 - 当键入路径或粘贴完整路径到旋转驱动器上的某个位置时,在 zsh 环境中运行的某些东西想要在我按 Enter 或 TAB 之前查看该驱动器,并且在驱动器旋转时它会被阻止。例如,我正在导航到
/media/drive-k/Apps
.如果我粘贴路径,shell 会阻塞。如果我输入它,当我A
在“应用程序”中输入时,shell 就会阻止。
因此,正如吉尔斯的答案所评论的,第一个测试是使用他的zsh -f
技巧并获得完整的普通 zsh 会话。绝对没有任何障碍,除非,例如,我按 TAB 或ls
旋转位置。我什至可以通过 TAB 切换到停止旋转的位置,而无需旋转驱动器,只要该位置已缓存在某处即可。例如,我可以使用 Tab 键/media/drive-d/Projects
切换到/media/drive-d/P<TAB>
,而驱动器 d 仍保持旋转状态。只有当我这样做时,ls -l
驱动器才会旋转。
好的。下一步是尝试 Gilles 的日志记录技巧。这个日志记录非常详细,并且启用了插件z
后,我收到了很多关于目录的令人困惑的日志,这些日志与我当时所在的位置完全无关。此外,在导航到阻止 shell 的路径时,日志保持沉默,直到块被释放,此时日志呈现大量输出,因此看起来阻塞是单个“外部操作”的一部分(也许这不是最好的措辞),它也封装了所有调试输出的收集。我本来希望看到日志显示一系列行,直到块的罪魁祸首开始运行,然后暂停,然后是更多行。
事实并非如此,我决定简单地禁用所有插件并尝试一一重新启用它们,同时尝试重复上述两个问题。我将所有驱动器上的旋转超时设置为 30 秒,使用sudo hdparm -S 6 /dev/disk/by-id/usb-*0:0
(我的目标是 USB 总线上的所有驱动器,使用0:0
后缀以避免尝试hdparm
针对这些驱动器上的分区使用(-S <num>
秒数为 num 的倍数) 5,所以 30 秒)。
这里的程序是编辑~/.zshrc
、禁用所有插件(我有plugins=(colored-man-pages git-extras history pj redis-cli urltools z zsh-syntax-highlighting)
)。然后,在两个新的 SHELL 中(以便读取更新的配置),导航到/media/drive-b/Projects
其中一个以便能够重现第二个问题,并导航到一个空白 shell/home/daniel
以便准备重现第一个问题。然后等待 30 秒并尝试这样做。
我可以确认,在没有加载插件的情况下,shell 没有重现这两个问题。
然后我简单地按顺序重新启用每个插件,直到找到罪魁祸首,然后按照描述打开新的 zsh 会话并等待超过 30 秒(同时立即认为 urltools 是罪魁祸首(因为 URL ~ 路径)(完全免责声明,我正在写在调试时使用过去时态,所以我还不知道,让我们看看我是否正确[悬疑音乐]))。
我错了。我一直坚持到最后,重新启用每个插件,以zsh-syntax-highlighting
.然后问题又出现了。我立即想到我在某种程度上错过了某些东西或错误地测试了某些东西(也许我忘记打开一个新的 shell 来读取更改?),所以我删除了zsh-syntax-highlighting
,并尝试更广泛地重现该问题。没问题。一切如常。
其实,这是有道理的。这是cd
一个在执行命令时变成绿色的插件。当您位于cdroms
其中的目录中时,它希望将其打印为灰色。我喜欢这个功能。但绝对不足以忍受这些缺点 XD。
天哪,我很高兴我的服务器恢复正常。谢谢你,吉尔斯,帮助我。希望其他人可以使用这个。