在 Bash 中,sleep 命令会让脚本的执行暂停一段指定的时间。它是 Shell 脚本中最常用的命令之一,尤其是在重试失败的操作、对一系列请求做限流,或在循环中加入短暂延迟时。
在本指南中,我们将通过实际示例演示如何使用 sleep 命令,包括如何让 sleep 暂停小数秒、如何组合多个时间单位,以及如何在后台运行 sleep。
语法
sleep 命令的语法如下:
sleep NUMBER[SUFFIX]...
NUMBER 可以是一个正整数或浮点数。
SUFFIX 可以是下列之一:
- s — 秒(默认)
- m — 分
- h — 时
- d — 天
如果不指定后缀,默认单位为秒。
当给定两个或更多参数时,总时长等于各参数值之和。
sleep 命令示例
下面这些示例展示了 sleep 命令的基本形式。
暂停指定秒数
要让脚本等待指定的秒数,直接传入不带后缀的数字即可。下面的命令会让执行延迟 5 秒:
sleep 5
暂停不足一秒(小数秒)
对于不足一秒的延迟,可以传入一个小数:
sleep 0.5
组合多个时长
可以组合多个值。下面这条命令会暂停 2 分 30 秒:
sleep 2m 30s
无限期暂停
要让进程无限期暂停,直到被手动中断,可以使用 infinity:
sleep infinity
这在 Docker 容器和 systemd 服务中很常见,用于在几乎不占用 CPU 的情况下让进程保持运行。
脚本示例
下面这些示例展示了 sleep 在 Bash 脚本中的常见用法。
计时延迟
这个脚本会在 5 秒延迟前后分别打印时间:
#!/bin/bash # start time date +"%H:%M:%S" # sleep for 5 seconds sleep 5 # end time date +"%H:%M:%S"
运行该脚本时,它会先以 HH:MM:SS 格式打印当前时间。随后 sleep 命令让脚本暂停 5 秒。指定的时间过后,最后一行会打印当前时间。
13:34:40 13:34:45
等待主机上线
下面的脚本每 5 秒检查一次某台主机是否在线,并在其可达时通知你:
#!/bin/bash
while :
do
if ping -c 1 192.168.1.10 &> /dev/null
then
echo "Host is online"
break
fi
sleep 5
done
脚本的工作原理如下:
- while 循环以 : 作为条件无限运行。
- ping 命令向目标主机发送一个数据包。
- 如果主机可达,脚本会打印“Host is online”,并用 break 退出循环。
- 如果主机不可达,sleep 5 会让脚本暂停 5 秒后再重试。
指数退避重试
在重试失败的操作时,逐步增大每次尝试之间的延迟是一种良好的做法,可以避免压垮目标服务:
#!/bin/bash
max_retries=5
delay=1
for ((i = 1; i <= max_retries; i++)); do
if curl -s --fail https://example.com > /dev/null; then
echo "Request succeeded on attempt $i"
exit 0
fi
echo "Attempt $i failed. Retrying in ${delay}s..."
sleep "$delay"
delay=$((delay * 2))
done
echo "All $max_retries attempts failed."
exit 1
延迟从 1 秒开始,每次失败后翻倍:1s、2s、4s、8s、16s。
倒计时器
一个简单的倒计时器,会打印剩余的秒数:
#!/bin/bash
seconds=${1:-10}
for ((i = seconds; i > 0; i--)); do
printf "\rTime remaining: %d seconds " "$i"
sleep 1
done
printf "\rTime's up! \n"
运行该脚本时可传入一个可选的秒数:
bash countdown.sh 30
在后台运行 sleep
可以在后台运行 sleep,从而实现非阻塞的延迟:
sleep 10 &
echo "Sleep is running in the background with PID $!"
& 运算符会把进程放到后台运行。特殊变量 $! 保存着最后一个后台进程的 PID。
要等待后台的 sleep 结束,可以使用 wait 命令:
sleep 10 &
pid=$!
echo "Doing other work..."
wait "$pid"
echo "Sleep finished"
暂停直到按键
在某些脚本中,你可能希望暂停直到用户按下某个键,而不是等待固定时长。sleep 命令本身做不到这一点,但你可以把它和 read 命令结合使用:
#!/bin/bash read -n 1 -s -r -p "Press any key to continue..." echo
-n 1 选项让 read 只接受一个字符,-s 不在终端回显按键,-r 则禁止对反斜杠进行转义解释。这是一种让脚本在继续之前等待用户确认的常见做法。
如果想要暂停直到按下按键,但没有人操作时也能自行继续,可以加上 -t 选项:
#!/bin/bash read -t 10 -n 1 -s -r -p "Press any key to continue (continuing in 10s)..." echo
脚本最多等待 10 秒让用户输入任意键,然后继续执行。同样的选项在读取值时也有效,例如 read -t 5 -p "Enter your name: " name 会给用户 5 秒时间输入姓名,超时后脚本将在没有该值的情况下继续。
中断 sleep
要中断正在运行的 sleep 命令,按下 Ctrl+C 即可。这会发送 SIGINT 信号来终止该进程。
要终止后台的 sleep 进程,可以使用 kill:
sleep 300 &
kill $!
快速参考
| 命令 |
|---|
| sleep 5 |
| sleep 0.5 |
| sleep 2m |
| sleep 1h 30m |
| sleep infinity |
| sleep 10 & |
| Ctrl+C 或 kill PID |
常见问题
sleep 是 bash 的内置命令吗?不是。sleep 命令由 GNU coreutils 软件包提供,位于 /usr/bin/sleep。因为它是一个外部程序而非 Shell 内置命令,所以 GNU 版本支持小数秒和 infinity 参数等不属于 POSIX 规范的特性。
sleep 能接受小数值吗?可以。Linux 上使用的 GNU 版 sleep 支持浮点数。例如,sleep 0.5 会暂停半秒。POSIX 规范只要求支持整数,因此在并非所有 Unix 系统上都能如此使用。
为什么 sleep 会报错 invalid time interval?这是因为参数不是一个数字后跟可选单位。常见原因包括数字与后缀之间多了空格(例如写成 sleep 2 m 而不是 sleep 2m)、使用了命令不支持的单位(如表示周的 w),或者变量被展开成了空字符串。在把变量传给 sleep 之前,应先给它加引号并打印其值确认。
sleep infinity 有什么用?sleep infinity 会无限期暂停进程,且不占用 CPU。它常用于 Docker 容器中以保持容器运行,或用于需要等待信号的脚本。
sleep 在等待时会占用 CPU 吗?不会。sleep 命令会挂起进程,在等待期间不消耗 CPU 周期。
如何在脚本中取消 sleep?按下 Ctrl+C 即可向前台进程发送 SIGINT。对于后台的 sleep 进程,则使用 kill PID,其中 PID 是 $! 返回的那个进程 ID。
总结
sleep 命令会让下一条命令的执行暂停一段指定的时间。它常用于 Shell 脚本中,以重试操作、限制请求频率以及调度延迟。
对于较长的脚本,请让延迟保持显式,并配合清晰的输出,这样你就能判断脚本当前是在等待、重试,还是已经结束。