【问题标题】:Bash: pause and continue execution with spacebarBash:使用空格键暂停并继续执行
【发布时间】:2017-10-01 08:45:58
【问题描述】:

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

【问题讨论】:

  • 您没有使用可以发送标准流控制信号(通常分别为^S^Q 来暂停和继续输出)的终端仿真器(例如xterm)吗?终端模拟器通常有一个回滚缓冲区(您通常也可以配置要存储多少回滚)。
  • 另外,一些通用的脚本建议:您可以通过将相关输出存储在循环外的变量中来减少您调用的tput 命令的数量。
  • @TobySpeight 我在 Ubuntu 上,通过 ssh 连接到批处理集群。你是什​​么意思将相关输出存储在变量中?代码的总输出是 >20k 行。
  • 我的意思是tput sc等每次循环都会产生相同的输出,所以你可以next=$(tput sc && tput cuu $(( $numberoflines +1 )) && ...); while read var; do echo; if; then echo "$next"; fi; done。但我仍然看不到你的脚本在做什么,而你的终端不能为你做。
  • 我的工作流程如下。我有一个提交 24 次计算的脚本,每一次计算大约需要一个小时,并且有 20k 行输出。我早上开始这个脚本,第二天再回来查看。现在,通常只有每个计算的最后一行输出是相关的,这是不可能在所有输出之间找到的(一天后将有 500k 行代码输出;现在尝试找到每个最后一行 - 所以每行一行20k-之间)。所以我最初所做的是将每个计算写入日志,当计算完成后,我输出最后一行......

标签: bash stty


【解决方案1】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-30
    • 1970-01-01
    • 1970-01-01
    • 2012-08-12
    相关资源
    最近更新 更多