为什么要睡觉并在bash中等待?

时间:2019-07-11 05:00:41

标签: bash docker

docker-compose.yml中,我无法理解服务的启动命令。 .yml中的两个相关行是:

command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

为什么将sleep命令发送到后台然后等待呢?为什么不直接直接sleep 6h?另外,双美元符号是否只是在${!}中逃脱了美元符号?

我正在寻找将睡眠和等待结合在一起使用的其他地方,但是似乎没有一个关于原因的解释:

  1. http://www.masteringunixshell.net/qa17/bash-how-to-wait-seconds.html
  2. https://stackoverflow.com/a/13301329/828584
  3. https://superuser.com/a/753984/98583

2 个答案:

答案 0 :(得分:5)

已编辑

当人们想及时处理信号时,有必要在后台休眠然后等待。

  

当bash在前台执行外部命令时,它会执行   在前台进程处理之前,不处理任何收到的信号   终止

(详细说明here)。

尽管第二个示例实现了一个信号处理程序,但对于第一个示例,无论是否在前台执行睡眠都没有区别。没有陷阱,信号也不会传播到nginx进程。 为了使其响应SIGTERM信号,入口点应该是这样的:

/bin/sh -c 'nginx -g \"daemon off;\" & trap exit TERM; while :; do sleep 6h  & wait $${!}; nginx -s reload; done'

要测试:

docker run --name test --rm --entrypoint="/bin/sh" nginx  -c 'nginx -g "daemon off;" & trap exit TERM; while :; do sleep 20 & wait ${!}; echo running; done'

停止容器

docker stop test

或发送TERM信号(如果主进程未退出,docker stop发送TERM,后跟KILL

docker kill --signal=SIGTERM test

这样做,脚本立即退出。现在,如果我们删除wait ${!},则在sleep结束时执行陷阱。在第二个示例中,所有方法也都很好。

注意:两种情况下的目的都是每12小时检查一次证书更新,并每6小时重新加载一次配置,如guide中所述 这两个命令就可以了。恕我直言,第一个示例中的额外等待只是开发人员的疏忽。

答案 1 :(得分:3)

我看到的唯一原因:

如果您killall -INT sleep,这不会影响主脚本。

尝试一下:

while true ;do sleep 12; echo yes;done

然后发送 Interrupt 信号:

killall -INT sleep

这会中断工作!

立即尝试

while true ;do sleep 12 & wait $! ; echo yes;done

然后再次:

killall -INT sleep

工作不会中断!

采样输出,从另一个窗口中击中killall -INT sleep

user@myhost:~$ while true ;do sleep 12; echo yes;done
break

user@myhost:~$ while true ;do sleep 12 & wait $! ; echo yes;done
[1] 30632
[1]+  Interrupt               sleep 12
yes
[1] 30636
[1]+  Interrupt               sleep 12
yes
[1] 30638
[1]+  Interrupt               sleep 12
yes
[1] 30640