如何在 Bash 中自定义错误消息的颜色?

hta*_*irt 9 linux bash

是否可以自定义 Bash 错误消息属性?

例如,是否可以编辑.bash_profile以获取以下 Bash 错误消息

-bash: cd: foo: No such file or directory
Run Code Online (Sandbox Code Playgroud)

红色的?

mr.*_*tic 4

遗憾的是,没有PS提示变量来控制 bash 错误的显示方式。

stderred是针对此类问题的综合解决方案,但如果不进行修改,它就无法工作,因为它有一个硬编码的排除bash请继续阅读以了解原因)。而且它有点侵入性(DLL 注入)。

hilite要求您将它用作包装器,这不适用于 bash 内置命令,例如cd.

您的问题专门询问 bash 错误消息,这些消息被发送到stderr,但stderr也与任何子进程(即任何其他命令)共享。我不确定你是否想区分两者。

这里隐藏的问题是bash它本身将提示和您的输入(回显)写入stderr. 证明:

bash              # start a sacrificial shell
exec 2> tmpfile   # change stderr to a file
ls                # you will see no prompt, and no command echo
... 
exit              # quit sacrificial shell
cat tmpfile       # contains PS1 prompt, your commands (and any errors too)
Run Code Online (Sandbox Code Playgroud)

内置调用(或至少应该调用)builtin_error()内部函数来打印错误,这无条件调用fprintf()stderr因此选项很少。

无需跳过麻烦或修补bash,突出显示错误的简单方法是:

function _t_debug() 
{
    if [ "${BASH_COMMAND:0:6}" != "_t_err" ]; then
        _lastcmd="$BASH_COMMAND"
    fi  
}
function _t_err() 
{
    local rc=$1 nn _type _argv
    #shift; pipe=($*)
    #if [ ${#pipe[*]} -gt 1 ]; then
    #    for ((nn=1; nn<=${#pipe[*]};nn++));do
    #        rc=${pipe[$((nn-1))]}
    #        echo -n "[$nn]=$rc ";
    #        ((rc >=128)) && echo -n "($((rc-128))) "
    #    done
    #fi

    read -a _argv <<< ${_lastcmd}
    _type=$(type -t "${_argv[0]}")

    if [ -n "$_lastcmd" ]; then
        tput setf 4
        printf 'Error %s: "%s"' "${_type}" "${_lastcmd:-unknown command}"
        tput sgr 0
        printf "\n"
    fi

    ((rc >=128)) && echo "[rc=$rc ($((rc-128)))]" ||
    echo "[rc=$rc]"
}
trap '_t_err $? ${PIPESTATUS[*]}' ERR
trap '_t_debug' DEBUG
Run Code Online (Sandbox Code Playgroud)

这使用 bashDEBUG陷阱在执行前缓存每个命令行,并ERR在非零时使用陷阱输出返回代码。但这对于某些 bash 内置命令(特别是复合命令while/case/for/if等等,请参阅手册页)不会。

我在我的 中使用了它的变体.profile,尽管我使用了pipe[]/PIPESTATUS[]上面注释掉的位,但它与上面介绍的 DEBUG 陷阱不兼容。如果注释掉,trap DEBUG则可以使用它来显示管道中每个命令的返回代码。

(另外,由于它被引用,所以command_not_found函数钩子是 bash-4.0+。)