我正在尝试使用以下方法分发很长的 make 输出
mkfifo myfifo
make 2>&1 | tee myfifo | grep -E "errors|warnings" myfifo > errors.log | cat myfifo
想法是输出的子集应该复制到日志文件,而整个输出将被重定向到控制台的标准输出。
一开始它似乎可以工作,但突然停止并保持冻结状态,直到我按 Ctrl-Z。
进程替换的使用
make 2>&1 | tee >(grep -E "errors|warnings" > errors.log)
不可能,因为 shell 编译时默认严格遵循 POSIX 标准。
platform - ubuntu 风格的发行版。 shell bash 4.2(只有一个可用)
答案1
那
make 2>&1 | tee myfifo | grep -E "errors|warnings" myfifo > errors.log | cat myfifo
P1 P2 P3
命令没有什么意义。它同时启动这 4 个命令,中间有管道:
make 2>&1
: stdout 和 stderr 转到 P1tee myfifo
:标准输入从 P1,标准输出到 P2。因此tee
将输出写入 P2myfifo
和 P2。grep -E "errors|warnings" myfifo > errors.log
: 来自 P2 的标准输入,但您将文件名 (myfifo
) 传递给grep
,因此grep
不会从其标准输入读取。标准输出转到errors.log
,没有写入 P3cat myfifo
: 来自 P3 的标准输入,但再次因为cat
给定了文件名,所以它会读取它。所以两者同时grep
读取。cat
myfifo
由于没有从 P2 读取任何内容,因此tee
当 P2 已满时将挂起。也不会显示已阅读的cat
部分。myfifo
grep
make 2>&1 | tee myfifo | grep -e errors -e warnings > errors.log | cat myfifo
我认为更接近你的意思。同样,P3 没有被使用,但我们使用 来|
并发启动cat
并等待它。
或者你可以这样做:
make 2>&1 | tee myfifo & grep -e errors -e warnings > errors.log
wait
如果需要更多grep
s,则需要更多 fifo:
make 2>&1 | tee fifo2grep1 fifo2grep2 &
grep errors fifo2grep1 > errors.log &
grep warnings fifo2grep2 > warnings.log
wait
在支持 的系统上/dev/fd/x
,您还可以执行以下操作:
make 2>&1 | { tee /dev/fd/3 | grep -e errors -e warnings 3>&-; } 3>&1
(这通常是进程替换在支持它的 shell 中所做的事情)。
如果是 2grep
秒,则变为:
make 2>&1 |
{
{
tee /dev/fd/3 /dev/fd/4 |
grep errors > errors.log 3>&- 4>&-
} 4>&1 |
grep warnings > warnings.log 3>&-
} 3>&1
答案2
之后grep -E "errors|warnings" myfifo > errors.log
管道不再包含数据。因此cat myfifo
从管道读取的下一个命令将被阻止。
如果我正确理解您的问题,您希望将所有消息打印到 stdout,并将所有错误和警告消息重定向到errors.log
.所以如果你想使用管道,请使用两个:
mkfifo pipe1 pipe2
make 2>&1 | tee pipe1 pipe2 | grep -E "errors|warnings" pipe1 > errors.log | cat pipe2