3

我正在运行在一个多小时内产生大量输出的代码。在执行期间,我使用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我相信可以通过使用(如在此线程中)将标准输入置于非阻塞模式来完成:

stty -echo -icanon time 0 min 0

但我无法将它与我现有的read.

一个重要的附带说明:我在 AFS 集群上,因此tee在计算完成之前我无法访问日志文件(由 编写),因为不同机器之间的同步是如何实现的(我知道否则会更容易tail -f在日志文件上使用 a )。

Ps:最有用的实现是,当按空格键暂停输出时,可以在输出中向上滚动以显示之前的行。欢迎提出任何建议,但我意识到这可能需要一个完全不同的实现,这可能会增加很多计算开销,所以我很高兴有一个解决方案可以通过空格键简单暂停。

4

1 回答 1

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不会等待整行,而是在收到字符后立即返回。我们需要readfrom /dev/tty(stderr 也可能这样做),因为我们期望来自 stdin 的管道输入,如somecmd | buf.

这里的缺点是,如果您停止输出太久,管道将停止并停止产生输出的过程。您可以通过在管道中使用pv(例如...| pv -qB 64k |...)作为缓冲区来解决此问题。虽然查看在读取端暂停时发送的输出有些困难。

如评论中所述,您也可以使用终端仿真器的缓冲来执行此操作。这将具有相同的缺点,即停止输出太长时间会再次停止管道的写入端。

于 2017-05-03T14:17:36.023 回答