我运行的代码在一个多小时内产生大量输出。在执行期间,我使用tee
将输出记录到文件中。然而,仍然发送到我的终端的大量输出有点麻烦,所以我做了一个小函数ShowLastLines
我可以管道我的输出,这将只显示最后15行的输出和更新实时。
这是剧本:
function ShowLastLines {
numberoflines=15
i=1
while read var
do
echo $var
if [ $i -gt $numberoflines ]
then
tput sc && tput cuu $(( $numberoflines +1 )) && tput dl 1 && tput rc && tput cuu 1
fi
(( i++ ))
done
}
在实践中,我这样使用它:
( long code ) 2>&1 | tee output.log | ShowLastLines
这可以很好地按预期工作,但是我想添加一个功能,即当我点击空格键时我想暂停输出(在ShowLastLines
中,当然不在原始执行中)例如,调查我注意到的一些细节,并在我再次点击空格键时继续它(它会赶上执行输出)。
我尝试了一些东西,但到目前为止还没有成功。我相信可以通过使用stty
(如this thread中)将标准输入置于非阻塞模式来完成:
stty -echo -icanon time 0 min 0
但我无法将其与现有的read
结合使用。
一个重要的侧面评论:我在AFS集群上,因此我无法访问日志文件(由tee
编写)直到计算完成,因为不同机器之间的同步是如何实现的(我知道)否则在日志文件中使用tail -f
会更容易。
Ps:最有用的实现是,当通过按空格键暂停输出时,可以在输出中向上滚动以显示之前的行。任何建议都是受欢迎的,但我意识到这可能需要一个完全不同的实现,可能会增加大量的计算开销,所以我很高兴有一个解决方案,通过空格键简单地暂停。
答案 0 :(得分:2)
最好使用select()
实际程序来同时读取管道和用户的输入。
但是,在Bash脚本中,您可以使用read
并使用较小的超时来检查用户是否已按下某个键:
buf() {
stty -echo < /dev/tty
while read line ; do
echo "$line"
if read -n1 -t0.0001 -u3 3</dev/tty ; then
echo paused.
read -n1 -u3 3</dev/tty
fi
done
stty echo < /dev/tty
}
read -n1
不会等待整行,但会在收到一个字符后立即返回。我们需要来自read
的{{1}}(stderr也可以),因为我们期望来自stdin的管道输入,如/dev/tty
中所示。
这里的缺点是如果你停止输出太长时间,管道将停止并停止产生输出的过程。您可以通过在管道中使用pv
(例如,somecmd | buf
)来充当缓冲区来解决此问题。虽然查看读取端暂停时发送的输出有点困难。
如评论中所述,您也可以使用终端模拟器的缓冲来执行此操作。这将具有相同的缺点,即停止输出太长时间将再次停止管道的写入侧。