关于bash:用另一个脚本处理stderr

handle stderr with another script

本问题已经有最佳答案,请猛点这里访问。

我有一个脚本(例如,compute.sh)在我的Ubuntu 16.04上做了一些事情并且可能以错误结束,让我们说:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[compute.sh]

#!/bin/bash

...

MISCELLANEOUS OPERATIONS

...

[if error occours]
echo"Error 55a">&2;
exit 1;

...

echo"Execution ok";
exit 0;

和另一个处理错误的脚本(例如error_handler.sh)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[error_handler.sh]

error=$(cat)

for i in"$@"
do
case $i in
    -u=*|--user=*)
    username="${i#*=}"
    shift
    ;;
    -t=*|--task=*)
    task="${i#*=}"
    shift
    ;;
esac
done

...

SENDS ERROR REPORTING THROUGH AN API LISTENING REMOTELY

...

我想执行compute.sh,将其stderr重定向到error_handler.sh,以便通知我的API系统出现错误

如果我尝试这个测试:

1
user@ubuntu: echo"test message" | ./error_handler.sh --user=dude --task="simple task"

我的error_handler.sh脚本接受字符串"test message"并正确处理它

如何只将stderr输出重定向到我的error_handler.sh脚本?

编辑:因为有时compute.sh可能会失败而没有错误消息(只需执行退出1;)我不确定error = $(cat)是否是在error_handler.sh中捕获错误消息的正确方法。 还有其他选择吗?

EDIT2:任务可以在crontab中执行,所以我需要在同一个命令中完成所有操作


最简单的方法是创建一个命名管道作为两者之间的缓冲区。

1
2
3
mkfifo errors           #"errors" is an arbitrary file name
compute.sh 2> errors &  # Run in the background
error_handler.sh < errors

作为一行:

1
mkfifo errors; compute.sh 2> errors & error_handler.sh

现在两个进程同时运行,error_handler.sh可以从errors读取,因为compute.sh写入它。缓冲区的大小有限,因此如果compute.sh变满,compute.sh将自动阻塞。一旦error_handler.sh消耗一些输入,compute.sh将自动恢复。只要错误不会产生太快(即,error_handler.sh可以处理错误),compute.sh就会像缓冲区一样无限运行。

如果缓冲区被清空,error_handler.sh将阻塞,直到有更多输入可用,或者直到compute.sh通过退出关闭其管道末端。

常规管道语法foo | bar创建一个匿名管道(或未命名的管道),它只是一个快捷方式

1
2
3
mkfifo tmp
foo > tmp &
bar < tmp

但是限制您将一个命令的标准输出连接到另一个命令的标准输入。使用其他文件描述符需要扭曲重定向。使用命名管道的类型稍长,但可以更清晰地阅读。