忽略 bash 中非常具体的错误消息

忽略 bash 中非常具体的错误消息

script.sh:

#!/bin/bash
my-bin-file-i-run

if [ $? -eq 0 ]
then
    exit 0
else
    if [[ >&2 == *"name_to_handle_at"* ]]; then
        exit 0
    fi
    echo >&2
    exit 1
fi

我想运行我的命令,如果它抛出一个错误,消息中包含“name_to_handle_at”,它将像脚本没有错误一样处理它,所有其他错误应该照常显示。无法真正让它发挥作用。

答案1

您的语法有错误,因为您不能仅将某些先前执行的命令的标准错误与==类似的进行比较。

一种建议是将错误流保存到文件中,然后解析该文件:

#!/bin/bash

if ! my-bin-file-i-run 2>error.log; then
    if ! grep -q -F 'name_to_handle_at' error.log; then
       echo 'some error message' >&2
       exit 1
    fi
fi

这将运行命令并将标准错误流重定向到名为error.log.如果命令因错误而终止,grep则用于name_to_handle_at在日志文件中查找字符串。如果找不到,则会打印一条错误消息,并且脚本以非零退出状态终止。

在任何其他情况下,脚本都会以零退出状态终止。

如果您希望error.log在脚本终止时删除该文件,您可以rm error.log在适当的位置或使用EXIT陷阱显式地执行此操作:

#!/bin/bash

trap 'rm -f error.log' EXIT

if ! my-bin-file-i-run 2>error.log; then
    if ! grep -q -F 'name_to_handle_at' error.log; then
       echo 'some error message' >&2
       exit 1
    fi
fi

答案2

您可以将程序的 stderr 通过管道传递给 grep 并使用 (bash 特定的)PIPESTATUS变量来区分命令成功/失败和命令打印/未打印该错误消息的 4 种组合:

{ your_command 2>&1 >&3 | grep your_error_message >/dev/null; } 3>&1
case ${PIPESTATUS[*]} in
0*) ;; # the command succeeded
*0) ;; # the command failed but printed the error message
esac

例子:

# usage wrapper pattern cmd args ...
wrapper(){
    msg=$1; shift
    { "$@" 2>&1 >&3 | grep "$msg" >/dev/null; } 3>&1
    case ${PIPESTATUS[*]} in
    0*|*0) return 0;;
    *) return "${PIPESTATUS[0]}";;
    esac
}

# usage test_cmd status error_message
test_cmd(){ status=$1; shift; echo >&2 "$@"; return "$status"; }

$ wrapper foo test_cmd 13 foo; echo $?
0
$ wrapper foo test_cmd 13 bar; echo $?
13

笔记:

不要将 替换grep >/dev/nullgrep -q;这将导致 grep 在第一次匹配时退出,并导致您的命令被 SIGPIPE 标记。

但是,您可以... | tee /dev/stderr | ...在命令和 grep 之间添加一个;这将导致错误消息被传递到 grep 并打印到 stderr。

许多低级程序(尤其是 python 脚本)将错误消息写入 stdout 而不是 stderr;如果是这种情况,你可以简单地使用

your_command 2>&1 | ...

而不是那些{ 2>&1 >&3 | ... } >&3fd 杂耍。

相关内容