ENV :GNU bash,版本 4.2.46(2)-release (x86_64-redhat-linux-gnu)(旧的)
- 我希望每个循环花费相同的时间。
- 循环永远不会停止
- 该
api_call
函数正常运行大约需要1s~5s。 - 由于网络问题,API 调用很少会挂起直到 60 秒超时。
我的脚本A
TIMEFORMAT=%R
while true; do
time=$(date +'%F %T')
api_result=$( { time api_call; } 2>api_runtime.txt )
api_runtime=$(cat api_runtime.txt)
echo "${time} ${api_result}"
sleep (( 10 - ${api_runtime} ))
done
我认为 Scrit A 会完成这项工作,直到有一天网络变慢并且循环不同步。
我的脚本B
TIMEFORMAT=%R
while true; do
time=$(date +'%F %T')
api_result=$( api_call & )
sleep 10
echo "${time} ${api_result:-No response}"
done
脚本 B 目前似乎也可以工作,但我不确定在下一个循环api_call
需要超过 10 秒时是否安全。
我该如何实现这一目标?
答案1
在命令替换内部使用&
不会与主脚本同时在后台运行该命令,只会运行该命令替换中发生的其他事情。
$ time str=$( (sleep 2; echo hello) & )
real 0m2.006s
user 0m0.000s
sys 0m0.003s
$ echo "$str"
hello
上面的作业在完成之前会挂起两秒钟,下面的作业也是如此。
$ time str=$( echo hello & sleep 2; echo bye )
real 0m2.011s
user 0m0.000s
sys 0m0.006s
$ echo "$str"
hello
bye
这意味着您sleep 10
没有必要(或者更确切地说,它总是会增加循环体的运行时间 10 秒),因为它前面的行上的赋值将阻塞,直到执行为止,这将在api_call
终止时发生。
如果您希望每次循环迭代花费 60 秒(您提到的超时长度):
while true; do
result=$( sleep 60 & api_call )
done
这确保了分配将花费 60 秒,即使api_call
返回时间比该时间短。
或者,
while true; do
result=$( sleep 10 & timeout 10s api_call )
done
api_call
...这需要 10 秒,如果比这慢,则显式发送 TERM 信号。
如果这是一个长时间运行的脚本,您会期望它会逐渐漂移。一个潜在的解决方案是使用 cron 作业定期重新安排它(终止正在运行的脚本并重新执行它)。