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/null
为grep -q
;这将导致 grep 在第一次匹配时退出,并导致您的命令被 SIGPIPE 标记。
但是,您可以... | tee /dev/stderr | ...
在命令和 grep 之间添加一个;这将导致错误消息被传递到 grep 并打印到 stderr。
许多低级程序(尤其是 python 脚本)将错误消息写入 stdout 而不是 stderr;如果是这种情况,你可以简单地使用
your_command 2>&1 | ...
而不是那些{ 2>&1 >&3 | ... } >&3
fd 杂耍。