我有一个运行bash脚本的任务调度程序。该任务首先打开一个GIT Bash终端,显示一条打开的消息("脚本即将在60秒内启动。")并在倒计时结束时运行一个脚本。
现在,我想改善用户体验,允许他/她停止/恢复倒计时或(无需任何干预)让脚本自动运行。所以,这是程序流程:
我已尝试使用read -p
,但这对我不利:我不希望用户采取措施解雇一些东西,而是停止/暂停倒计时(然后恢复它)。
答案 0 :(得分:3)
更新历史记录:
可暂停倒计时
结合类似问题here的一些提示和一些有关如何阅读单个字符(e.g. here, otherwise everywhere on the internet)的外部资源,并添加一个额外的恢复循环,这就是我提出的:
#!/bin/bash
# Starts a pausable/resumable countdown.
#
# Starts the countdown that runs for the
# specified number of seconds. The
# countdown can be paused and resumed by pressing the
# spacebar.
#
# The countdown can be sped up by holding down any button
# that is no the space bar.
#
# Expects the number of seconds as single
# argument.
#
# @param $1 number of seconds for the countdown
function resumableCountdown() {
local totalSeconds=$1
while (( $totalSeconds > 0 ))
do
IFS= read -n1 -t 1 -p "Countdown $totalSeconds seconds (press <Space> to pause)" userKey
echo ""
if [ "$userKey" == " " ]
then
userKey=not_space
while [ "$userKey" != " " ]
do
IFS= read -n1 -p "Paused, $totalSeconds seconds left (press <Space> to resume)" userKey
echo ""
done
elif [ -n "$userKey" ]
then
echo "You pressed '$userKey', press <Space> to pause!"
fi
totalSeconds=$((totalSeconds - 1))
done
}
# little test
resumableCountdown 60
可以将其保存并作为独立脚本运行。该功能可以在其他地方重复使用。它暂停/恢复SPACE
,因为这对我来说似乎更直观,因为它的工作方式如下:在嵌入浏览器的视频播放器中。
也可以通过按空格键以外的其他按键来加速倒计时(这是一项功能)。
发出警告消息并等待可暂停的超时
以下变体实现了可暂停超时,除了用户通过按空格键暂停或恢复(内部)倒计时之外,它只打印初始警告消息:
# Prints a warning and then waits for a
# timeout. The timeout is pausable.
#
# If the user presses the spacebar, the
# internal countdown for the timeout is
# paused. It can be resumed by pressing
# spacebar once again.
#
# @param $1 timeout in seconds
# @param $2 warning message
warningWithPausableTimeout() {
local remainingSeconds="$1"
local warningMessage="$2"
echo -n "$warningMessage $remainingSeconds seconds (Press <SPACE> to pause)"
while (( "$remainingSeconds" > 0 ))
do
readStartSeconds="$SECONDS"
pressedKey=""
IFS= read -n1 -t "$remainingSeconds" pressedKey
nowSeconds="$SECONDS"
readSeconds=$(( nowSeconds - readStartSeconds ))
remainingSeconds=$(( remainingSeconds - readSeconds ))
if [ "$pressedKey" == " " ]
then
echo ""
echo -n "Paused ($remainingSeconds seconds remaining, press <SPACE> to resume)"
pressedKey=""
while [ "$pressedKey" != " " ]
do
IFS= read -n1 pressedKey
done
echo ""
echo "Resumed"
fi
done
echo ""
}
warningWithPausableTimeout 10 "Program will end in"
echo "end."
更新同一行的可用倒计时
这是一个类似于第一个的倒计时,但它只需要一行。依靠echo -e
来删除和覆盖先前打印的消息。
# A pausable countdown that repeatedly updates the same line.
#
# Repeatedly prints the message, the remaining time, and the state of
# the countdown, overriding the previously printed messages.
#
# @param $1 number of seconds for the countdown
# @param $2 message
singleLinePausableCountdown() {
local remainingSeconds="$1"
local message="$2"
local state="run"
local stateMessage=""
local pressedKey=""
while (( $remainingSeconds > 0 ))
do
if [ "$state" == "run" ]
then
stateMessage="[$remainingSeconds sec] Running, press <SPACE> to pause"
else
stateMessage="[$remainingSeconds sec] Paused, press <SPACE> to continue"
fi
echo -n "$message $stateMessage"
pressedKey=""
if [ "$state" == "run" ]
then
IFS= read -n1 -t 1 pressedKey
if [ "$pressedKey" == " " ]
then
state="pause"
else
remainingSeconds=$(( remainingSeconds - 1 ))
fi
else
IFS= read -n1 pressedKey
if [ "$pressedKey" == " " ]
then
state="run"
fi
fi
echo -ne "\033[1K\r"
done
echo "$message [Done]"
}
如果线条比控制台宽度长(它不会完全擦除线条),这个可能会表现得很奇怪。
任何试图制作某人的人都没有收集提示。类似:
IFS= read -n1
读取单个字符read -t <seconds>
设置了read
的超时时间。超时到期后,read
将以非零退出,并将变量设置为空。$SECONDS
以秒为单位衡量脚本开始的时间。echo -n
打印了一行,则可以使用echo -ne "\033[1K\r"
删除并重置该行。