30 秒无用户输入后终止脚本?

Terminate script after 30 seconds of no user input?

我正在尝试创建一个简单的 Bash 脚本,该脚本在等待用户输入 10 秒后终止。如果用户输入某些内容,计时器将重置,10 秒规则再次适用。我正在使用 trap 来确保我的程序可以退出的唯一两种方式是:

  1. 我输入“停止”
  2. 用户未输入 10 秒

我尝试使用类似的东西:

{
sleep 10s
kill $$
} &

但是按下Ctrl-C后,10秒后程序并没有停止。它会无限期地继续下去。

您可以使用 read 的超时选项。但请注意,当用户按下某个键时,这不会重置,只有当他们按回车键完成输入时才会重置。

read -t 10 userinput || exit 1

如果您使用 set -e,则可以省略 || exit 1

read 可能因为其他原因而失败,所以你可以专门测试超时。超时错误代码大于 128。

read -t 10 userinput || { (($?>128)) && exit 1; }

if ! read -t 10 userinput && (($? > 128)); then
    echo 'you timed out' >&2
    exit 1
fi

如果 read 失败,您可能仍想退出。但是测试超时错误代码允许您打印相关的错误消息。

read有超时参数,可以使用:

read -t 30 answer

POSIX TTY 线路规程提供了这样一个功能:一个可配置的计时器,只要输入到达就会重置,并在超时时终止 read() 操作。当 TTY 处于原始模式时(例如来自串行线路),此计时器通常用于生成更大的读取。

这个 proof-of-concept 解决方案中有一些棘手的事情。它处理 Ctrl-Z 暂停在读取期间工作的要求,并重置计时器:

#!/bin/sh

# save the TTY settings, to restore later
# this should ideally be done in an exit/interrupt trap.
saved_tty=$(stty -g)

# initialize some variables
resumed=            # flag indicating Ctrl-Z resume
biginput=           # total input collected
littleinput=        # input from one read operation

# function to set a special TTY mode, and set the resumed flag
set_tty_mode()
{
  # turn of canonical mode; set up 10 second timer (100 x 0.1s)
  # min 0 means read a minimum of 0 bytes, allowing timer to work

  stty -icanon min 0 time 100 

  # setting this flag plays a role when this function is called
  # as the SIGCONT interrupt handler.
  resumed=y
}

# switch to above TTY mode
set_tty_mode

# when the SIGCONT signal goes off, indicating we resumed from Ctrl-Z
# suspend, call set_tty_mode. This is because when we are suspended,
# the shell, e.g. Bash, messes with the TTY settings.
trap set_tty_mode CONT

# no we loop, reading into the littleinput variable.
while true ; do
  resumed=                          # clear the flag
  read littleinput                  # read input
  biginput="$biginput$littleinput"  # accumulate
  [ $resumed ] || break             # terminate loop, unless SIGCONT happened
done

printf "read: [%s]\n" "$biginput"

stty $saved_tty