Bash:暂停并使用空格键继续执行

Bash: pause and continue execution with spacebar

我是 运行 一个多小时内产生大量输出的代码。在执行期间,我使用 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

这按预期工作得很好,但是我想再添加一项功能,即我想在按下空格键 (例如,调查我注意到的一些细节),并在我再次按下空格键时让它继续(它将赶上执行输出)。

我尝试了一些东西,但到目前为止还没有成功。我相信可以通过使用 stty(如 this thread)将标准输入置于非阻塞模式来完成:

stty -echo -icanon time 0 min 0

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

结合起来

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

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

这可能最好通过使用 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 不会等待整行,而是会在接收到一个字符后立即 return。我们需要从 /dev/tty read(stderr 也可能这样做),因为我们期望来自 stdin 的管道输入,如 somecmd | buf.

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

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