前几天在工作中,我们有一个 Bash 脚本,用于设置一个 Web 服务器,并等待它启动后再继续执行后续操作。这个脚本运行正常,我们也没有遇到任何问题,直到出现了一个无限循环。
我们使用 Bash 内置的 until
来检查 Web 服务器是否正常:
until curl --silent --fail-with-body 10.0.0.1:8080/health; do
sleep 1
done
这很好用。除非我们的 Web 服务器在启动过程中崩溃,并且我们 sleep 1
永远等待。
这里有一个实用的工具:timeout
。顾名思义,这个命令可以为其他命令添加超时功能。您指定想要等待命令的时间限制,如果该时间已过,timeout
会发送一个信号来终止它,并以非零状态退出。默认情况下,timeout
发送的是 SIGTERM
信号,但您可以通过 --signal
标志来更改它,例如 timeout --signal=SIGKILL 1s foo
。
例如,timeout 1s sleep 5
将向 sleep
发送 SIGTERM
信号 1秒后:
$ time timeout 1s sleep 4
real 0m1,004s
user 0m0,000s
sys 0m0,005s
$ echo $?
124
那么接下来应该将 timeout
和 until
结合起来:
timeout 1m until curl --silent --fail-with-body 10.0.0.1:8080/health; do
sleep 1
done
唯一的问题是这行不通。timeout
需要一个可终止的命令,而 until
是一个 shell 关键字:你不能 SIGTERM
until``。我们无法使用 timeout
与任何 shell 内建命令一起使用。
前进的方向是将那个 until
包裹在一个 Bash 进程中:
timeout 1m bash -c "until curl --silent --fail-with-body 10.0.0.1:8080/health; do
sleep 1
done"
另一种方法是将要移动到单独的 Bash 脚本中的 until
,并使用 timeout
it:
timeout 1m ./until.sh
很遗憾我们无法直接使用 timeout
与 until
结合,那将非常方便。但将其包装在 Bash 进程/脚本中即可完成任务。