我为命令行编写了钩子:
# Transforms command 'ls?' to 'man ls'
function question_to_man() {
if [[ $2 =~ '^\w+\?$' ]]; then
man ${2[0,-2]}
fi
}
autoload -Uz add-zsh-hook
add-zsh-hook preexec question_to_man
但是当我这样做时:
> ls?
退出man
后,我得到:
> zsh: no matches found: ls?
如何摆脱有关错误命令的消息?
答案 0 :(得分:5)
?
对于 zsh 是特殊的,并且是单个字符的通配符。这意味着,如果您键入ls?
zsh ,尝试在当前目录中找到匹配的文件名(任何以&#34开头的三个字母名称; ls")。
有两种方法可以解决这个问题:
你可以制作"?" " unspecial"引用它:ls\?
,'ls?'
或"ls?"
。
让 zsh 处理不匹配的情况:
如果找不到匹配项,则默认行为是打印错误。这可以通过禁用NOMATCH
选项进行更改(同时也不能设置NULL_GLOB
):
setopt NO_NOMATCH
setopt NO_NULL_GLOB
如果没有匹配的文件,这将使单词保持不变。
警告:在(可能不太可能)存在具有匹配名称的文件的情况下, zsh 将尝试执行具有第一个匹配名称的命令文件。也就是说,如果有一个名为" lsx"的文件,那么ls?
将被lsx
替换,zsh将尝试运行它。这可能会或可能不会失败,但很可能不会产生预期的效果。
这两种方法都有其优点和缺点。 1.可能不是你正在寻找的东西,2。每次都不起作用,也不会改变你的炮弹行为。
另外(正如@chepner在他的评论中指出的那样)preexec
另外运行而不是命令。这意味着您可以获得ls
的帮助,但 zsh 仍会尝试运行ls?
甚至lsx
(或其他匹配的名称)。
为避免这种情况,我建议您定义一个command_not_found_handler
函数而不是preexec
。来自zsh manual:
如果未找到外部命令但存在函数
command_not_found_handler
,则shell将使用所有命令行参数执行此函数。如果成功处理命令,该函数应返回状态零,如果失败,则返回非零状态。在后一种情况下,应用标准处理:'command not found'打印到标准错误,shell退出状态127.注意,处理程序在子shell中执行,分叉执行外部命令,因此更改为目录,shell参数等对主壳没有影响。
所以这应该可以解决问题:
command_not_found_handler () {
if [[ $1 =~ '\?$' ]]; then
man ${1%\?}
return 0
else
return 1
fi
}
如果您有很多匹配的文件名但很少会错误输入命令(通常的原因" Command not found"错误),您可能需要考虑使用它:
command_not_found_handler () {
man ${1%?}
}
这不会检查"?"最后,但只是删除任何最后一个字符(注意缺少" \"在${1%?}
中)并尝试在其余字符上运行man
。因此,即使文件名匹配,也会运行man
,除非确实存在与匹配文件同名的命令。
注意:这会干扰使用command_not_found_handler
的其他工具,例如来自Ubuntu的command-not-found
工具(如果为zsh启用)。
总而言之, zsh 有一个名为run-help
的小部件,可以绑定到一个键(在Emacs模式下,它默认绑定到 Alt + H )而不是为当前命令运行man
。
在上面使用run-help
的主要优点是:
您甚至可以将其绑定到 Alt + ?以使其更相似:bindkey '^[?' run-help