通过 FIFO 分配输出

通过 FIFO 分配输出

我正在尝试使用以下方法分发很长的 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 转到 P1
  • tee myfifo:标准输入从 P1,标准输出到 P2。因此tee将输出写入 P2myfifo和 P2。
  • grep -E "errors|warnings" myfifo > errors.log: 来自 P2 的标准输入,但您将文件名 ( myfifo) 传递给grep,因此grep不会从其标准输入读取。标准输出转到errors.log,没有写入 P3
  • cat myfifo: 来自 P3 的标准输入,但再次因为cat给定了文件名,所以它会读取它。所以两者同时grep读取。catmyfifo

由于没有从 P2 读取任何内容,因此tee当 P2 已满时将挂起。也不会显示已阅读的cat部分。myfifogrep

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

如果需要更多greps,则需要更多 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

相关内容