我可以让 bash 在存在前导 `:` 时忽略它吗?

我可以让 bash 在存在前导 `:` 时忽略它吗?

通常,如果我在 bash(在 macOS 上)中工作,我也会在 (Mac)Vim 中工作,在两者之间切换。从 Vim 切换到终端后我常犯的一个错误是在命令前包含一个前导冒号。我将:cd /path/to/project/dir/在 Vim 中,然后切换到终端并输入完全相同的内容,当然,我不应该在那里以冒号开头。

所以,我不知道什么时候 bash 命令应该以冒号开头,并且每次我不是故意的。那么,有没有办法让 bash 完全忽略冒号(如果它是命令中的第一个字符)并将其解释:cd ...cd ...

答案1

bash(1)command_not_found_handle()如果已定义并且未找到要执行的命令,则将调用该函数。如果您尚未使用此功能(例如 Ubuntu 上的 command-not-found 软件包),您可以使用它来去掉冒号并重试:

command_not_found_handle() {
    if [[ "${1:0:1}" != : ]]; then
        printf "%s: %s: command not found\n" "$0" "$1" >&2
        return 127
    else
        "${1/#:}" "${@:2}"
    fi
}

将该函数放入您的.bashrc.然后,当未找到以冒号开头的命令时,它将去掉前面的冒号并重试。

编辑:我会进一步解释一下,因为这里有一些不常见的扩展。

首先,正如评论中所指出的,command_not_found_handle这是 bash 4 的一个功能。 Bash 4 于 2009 年 2 月发布。command_not_found_handle使用未找到的命令和该命令的参数来调用该函数。 ie$1是未找到的命令,$2之后是未找到的命令的参数。这在下面描述命令执行在手册页中。

"${1:0:1}"是一个扩展,它从 , 从位置 0 开始长度为 1 的子字符串$1。也就是说,它从 中提取第一个字符$1,其中$1是未找到的命令。这记录在参数扩展在手册页中为${parameter:offset:length}.

如果 的第一个字符$1不是冒号,我们会打印一个错误并返回退出值 127。 127 是 bash 在找不到要执行的命令时使用的退出代码,如下所示命令执行在手册页中。

"${1/#:}"扩展为$1并去掉任何前导冒号。如果开头没有冒号,则它相当于一个普通的$1,但由于我们所处的条件的分支,我们知道它无论如何都以冒号开头。此扩展记录在参数扩展在手册页中的${parameter/pattern/string}部分中。

"${@:2}"从第二个开始扩展到位置参数。此扩展记录在参数扩展在手册页中的${parameter:offset}部分,作为数组和 的特殊情况@。也就是说,它不是提取子字符串,而是扩展到数组的元素。

最终结果是,如果运行未找到的命令并且该命令有一个前导冒号,我们将去掉冒号以形成一个新命令,并将原始参数传递给新命令。这最终将以递归方式工作,就好像未找到第二次运行命令的尝试一样,command_not_found_handle()将再次执行。这意味着您可以运行:::mkdir并且它仍然会运行mkdir

相关内容