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

时间:2017-05-03 13:24:56

标签: bash stty

我运行的代码在一个多小时内产生大量输出。在执行期间,我使用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:最有用的实现是,当通过按空格键暂停输出时,可以在输出中向上滚动以显示之前的行。任何建议都是受欢迎的,但我意识到这可能需要一个完全不同的实现,可能会增加大量的计算开销,所以我很高兴有一个解决方案,通过空格键简单地暂停。

1 个答案:

答案 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)来充当缓冲区来解决此问题。虽然查看读取端暂停时发送的输出有点困难。

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