Bash脚本监听按键以继续移动。

17

我想编写一个bash脚本,其中包含一系列步骤,并将其标识为“任务#”。但是,只要用户愿意,每个步骤都可以完成并运行。

Do task1
if keypressed stop task1 and move on #this is the part I need help with. There can be up to 10 of these move on steps. 
Do task2
...

这有点像顶部;它会一直做某些事情,直到按下q键退出,但我想要前进到下一个步骤。


while循环子集:https://dev59.com/DG435IYBdhLWcg3wpxyw - Ciro Santilli OurBigBook.com
2个回答

18
你可以使用带有选项-t-n的内置命令read
while :
do
    # TASK 1
    date
    read -t 1 -n 1 key

    if [[ $key = q ]]
    then
        break
    fi
done

# TASK 2
date +%s

1
@jarno:感谢您的纠正和指引。我已经删除了我的原始评论,并决定深入研究我的答案。 - mklement0

6

kev的优秀解决方案即使在Bash 3.x中也能很好地工作。,但是它在每个循环迭代中引入了1秒的延迟(-t 1).

Bash 3.x中,-t(超时)的最低支持值是1(秒),不幸的是。

Bash 4.x支持0小数

一个支持q等任意键的解决方案需要一个非零-t值,但你可以指定一个非常接近0的值来使延迟最小化

#!/bin/bash
# !! BASH 4.x+ ONLY

while :; do

  # Loop command
  date

  # Check for 'q' keypress *waiting very briefly*  and exit the loop, if found.
  read -t 0.01 -r -s -N 1 && [[ $REPLY == 'q' ]] && break

done

# Post-loop command
date +%s
注意:以上使用 0.01 作为几乎没有超时的值,但是根据您的主机平台、终端程序以及可能存在的CPU速度/配置,可能需要更大的值 / 可能支持更小的值。如果值太小,您将看到间歇性的error setting terminal attributes: Interrupted system call错误 - 如果有人知道原因,请告诉我们。
jarno 致敬,他在以下方面提供了帮助:

使用 -t 0,根据 help read(已加粗),其工作方式如下:

如果 TIMEOUT 是 0,则 立即返回 而不尝试读取任何数据,只有在指定的文件描述符上有输入可用时才 返回成功

从Bash v4.4.12和5.0.11开始,不幸的是,-t 0似乎会忽略-n/-N,因此只有按下ENTER键(或以ENTER键结尾的一系列按键)会导致read指示数据可用。
如果有人知道这是一个bug还是这种行为有充分的理由,请告诉我们。

因此,只有以ENTER作为退出键才能使用-t 0解决方案

#!/bin/bash
# !! BASH 4.x+ ONLY

while :; do

  # Loop command
  date

  # Check for ENTER keypress and, after clearing the input buffer
  # with a dummy `read`, exit the loop.
  read -t 0 -r -N 1 && { read -r; break; }

done

# Post-loop command
date +%s

1
在这里搜索并研究“设置终端属性”错误,从bash -o monitor -c 'read -t1 -n1 -s -pp: r &'(NB -o monitor for &)中,我发现错误来自于builtins/read.def在builtins/common.c中调用sh_ttyerror(1),当一些由grep -EHn 'tt(setattr|_set(cbreak|onechar|noecho))'匹配的调用在lib/sh/shtty.c失败时。(删除-s可以避免一个错误。)添加-e以使用readline对我来说可以避免任何错误。 - vike
谢谢,@vike。根据你的发现,有没有办法让上述内容与“-t 0”一起工作? - mklement0
1
不,关于 -t0 的信息是正确的(作为 read.def 中的特殊情况,在独立于其他选项的情况下)。虽然我发现我的 bash 5.0.7似乎支持 -t0.001-n1,但只有 -N1-t0.0001(与 -s 和 / 或 -r 无关)。奇怪的是,只有 -t0.00001 似乎受到支持,但是仅具有 -e,只有 -t0.002233 会被支持。这些分数可能取决于本地 CPU 时间,因为 setitimer(3) 四舍五入到“系统时钟的分辨率”(在我的 '93 manpage 中通常为10毫秒),并且在 read.def 的不同位置使用 CHECK_ALRM 宏(来自 quit.h)。 - vike
感谢您深入挖掘,@vike。考虑到您已经做了这么多研究,我鼓励您提交一个关于“-t 0”的详细错误报告(例如通过“bashbug”脚本)。 - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接