linux - 如何防止在 ZSH 中执行命令?

标签 linux zsh

我为命令行写了钩子(Hook):

# 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?

如何摆脱有关错误命令的消息?

最佳答案

?zsh 是特殊的,是单个字符的通配符。这意味着如果您键入 ls? zsh 会尝试在当前目录中查找匹配的文件名(任何以“ls”开头的三个字母的名称)。

有两种方法可以解决这个问题:

  1. 你可以制作“?”通过引号表示“不特殊”:ls\?'ls?'"ls?"

  2. 你让 zsh 更好地处理不匹配的情况:

    如果找不到匹配项,默认行为是打印错误。这可以通过禁用 NOMATCH 选项来改变(也不能设置 NULL_GLOB):

    setopt NO_NOMATCH
    setopt NO_NULL_GLOB
    

    如果没有匹配的文件,这将保持单词不变。

    警告:在(可能不太可能)存在具有匹配名称的文件的情况下,zsh 将尝试执行具有第一个匹配名称的命令文件。也就是说,如果有一个名为“lsx”的文件,那么 ls? 将被替换为 lsx 并且 zsh 将尝试运行它。这可能会也可能不会失败,但很可能不会达到预期的效果。

这两种方法各有利弊。 1. 可能不完全是您要找的东西,并且 2. 并非每次都有效,并且会改变您的 shell 行为。


另外(正如@chepner 在他的评论中指出的那样)preexec 额外运行而不是命令。这意味着您可以获得 ls 的帮助,但 zsh 仍会尝试运行 ls? 甚至 lsx(或其他匹配名称)。

为避免这种情况,我建议定义一个 command_not_found_handler 函数而不是 preexec。来自zsh manual :

If no external command is found but a function command_not_found_handler exists the shell executes this function with all command line arguments. The function should return status zero if it successfully handled the command, or non-zero status if it failed. In the latter case the standard handling is applied: ‘command not found’ is printed to standard error and the shell exits with status 127. Note that the handler is executed in a subshell forked to execute an external command, hence changes to directories, shell parameters, etc. have no effect on the main shell.

所以这应该可以解决问题:

command_not_found_handler () {
    if [[ $1 =~ '\?$' ]]; then
        man ${1%\?}
        return 0
    else
        return 1
    fi
}

如果您有很多匹配的文件名,但很少输入错误的命令(“找不到命令”错误的常见原因),您可能需要考虑改用它:

command_not_found_handler () {
    man ${1%?}
}

这不会检查“?”最后,只是删除最后一个字符(注意 ${1%?} 中缺少的“\”)并尝试在其余部分运行 man。因此,即使文件名匹配,man 也会运行,除非确实存在与匹配文件同名的命令。

注意:这会干扰使用 command_not_found_handler 的其他工具,例如来自 Ubuntu 的 command-not-found 工具(如果为 zsh 启用) ).


综上所述,zsh 有一个名为 run-help 的小部件,它可以绑定(bind)到一个键(在 Emacs 模式下,它默认绑定(bind)到 Alt+H) 然后为当前命令运行 man

使用 run-help 的主要优点是:

  1. 您可以在键入较长命令时随时调用它,只要命令名称完整即可。
  2. 离开联机帮助页后,命令仍未更改,因此您可以继续在上面书写。

您甚至可以将其绑定(bind)到 Alt+? 以使其更相似:bindkey '^[?'运行帮助

关于linux - 如何防止在 ZSH 中执行命令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30028730/

相关文章:

linux - 如何防止编译器和链接器接管整个机器?

linux - 压缩 Web Root : Why didn't nice reduce CPU load?

git - 如何让 'git status' 始终使用短格式?

macos - ZSH 'Sticky' 提示符

ruby-on-rails - 为什么,rails 服务器没有在 zsh 终端中运行?

linux - 使用 nc 传输大文件

linux - 将所有文件类型写入文件 - ubuntu

linux - 4 行在包含许多文件的目录中反转 grep 搜索

macos - 如何安全地解决 Homebrew 软件和 zsh 对/usr/local/share/zsh 所有权的冲突需求?

bash - 如何在远程服务器上为 git commit、git pull、git push 和 pull 创建 bash 或 zsh 别名?