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 |...
)作为缓冲区来解决此问题。虽然在阅读端暂停时查看发送的输出有些困难。
如评论中所述,您也可以使用终端仿真器的缓冲来执行此操作。这将有同样的缺点,即停止输出太久会再次停止管道的写入端。
我是 运行 一个多小时内产生大量输出的代码。在执行期间,我使用 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 |...
)作为缓冲区来解决此问题。虽然在阅读端暂停时查看发送的输出有些困难。
如评论中所述,您也可以使用终端仿真器的缓冲来执行此操作。这将有同样的缺点,即停止输出太久会再次停止管道的写入端。