对于这个具有挑战性的问题,这里给出了一些有趣的想法,但到目前为止我还没有看到任何完整的解决方案。我会试着给一个。为了实现这一点,我先写了三个脚本,对应着 PO 所说的管道prog1 | prog2 | prog3。
prog1 在错误流上生成由\n 分隔的消息并在标准流上生成数字:
#!/bin/bash
cmd=$(basename $0)
seq 8 |
while ((i++ < 10)); do
read line || break
echo -e "$cmd: message $i to stderr" >&2
echo $line
sleep 1
done
echo -e "$clearline$cmd: has no more input" >&2
prog2 生成由\r 分隔的消息,并在错误流上覆盖其自己的输出,并将数字从标准输入流传输到标准输出流:
#!/bin/bash
cmd=$(basename $0)
el=$(tput el)
while ((i++ < 10)); do
read line || break
echo -en "$cmd: message $i to stderr${el}\r" >&2
echo $line
sleep 2
done
echo -en "$clearline$cmd: has no more input${el}\r" >&2
最后是 prog3 从标准输入流读取并将消息写入错误流,方法与 prog2 相同:
#!/bin/bash
cmd=$(basename $0)
el=$(tput el)
while ((i++ < 10)); do
read line || break
echo -en "$cmd: message $i to stderr${el}\r" >&2
sleep 3
done
echo -en "$clearline$cmd: has no more input${el}\r" >&2
而不是调用这三个脚本
prog1 | prog2 | prog3
我们需要一个脚本来调用这三个程序,将错误流重定向到三个 FIFO 特殊文件(命名管道),但在启动此命令之前,我们必须首先创建三个特殊文件并在后台进程中启动收听特殊文件:每次发送整行时,这些过程都会将其打印在屏幕的特殊区域上,我将其称为任务栏。
三个任务栏在屏幕底部:上面的一个将包含prog1到错误流的消息,下一个将对应于prog2,底部的最后一个将包含消息来自prog3。
最后,必须删除 FIFO 文件。
现在是棘手的部分:
- 如果没有缓冲以
\r 结尾的行,我发现没有实用程序读取,因此我必须在将消息行打印到屏幕之前将\r 更改为\n;
- 我用管道连接的几个程序中的一些程序正在缓冲它们的输入或输出,导致消息直到最后才被打印,这显然不是预期的行为;为了解决这个问题,我必须使用命令
stdbuf 和 tr 实用程序;
综上所述,我实现了下一个脚本,它按预期工作:
#!/bin/bash
echo -n "Test with clean output"
echo;echo;echo # open three blank lines in the bottom of the screen
tput sc # save the cursor position (bottom of taskbars)
l3=$(tput rc) # move cursor at last line of screen
l2=$(tput rc; tput cuu1) # move cursor at second line from bottom
l1=$(tput rc; tput cuu1; tput cuu1) # move cursor at third line from bottom
el=$(tput el) # clear to end of line
c3=$(tput setaf 1) # set color to red
c2=$(tput setaf 2) # set color to green
c1=$(tput setaf 3) # set color to yellow
r0=$(tput sgr0) # reset color
mkfifo error{1..3} # create named pipes error1, error2 and error3
(cat error1 | stdbuf -o0 tr '\r' '\n' |
while read line1; do echo -en "$l1$c1$line1$el$r0"; done &)
(cat error2 | stdbuf -o0 tr '\r' '\n' |
while read line2; do echo -en "$l2$c2$line2$el$r0"; done &)
(cat error3 | stdbuf -o0 tr '\r' '\n' |
while read line3; do echo -en "$l3$c3$line3$el$r0"; done &)
./prog1 2>error1 | ./prog2 2>error2 | ./prog3 2>error3
wait
rm error{1..3} # remove named pipes
tput rc # put cursor below taskbars to finish gracefully
echo
echo "Test finished"
我们为任务栏的每一行添加了不同的颜色,字符串由tput 生成。
享受吧。