Docker Compose运行Shell脚本时$SECONDS变量失效报错排查
问题根因
$SECONDS是Bash Shell专属的内置变量,(( ))双括号算术判断语法也是Bash独有的特性。
你在容器中执行脚本时默认调用的是/bin/sh,绝大多数Docker基础镜像(Alpine、Debian Slim等)中的/bin/sh是dash、ash这类轻量POSIX标准Shell,既不内置$SECONDS变量,也不支持双括号算术语法。这种环境下$SECONDS取值为空,判断语句里的<会被解析为文件重定向符,整段逻辑就变成尝试打开名为120的文件读取输入,最终抛出你看到的can't open 120: no such file报错。
可用解决方案
方案1:显式使用Bash执行脚本(保留原有$SECONDS写法)
- 修改脚本第一行的shebang声明,替换为Bash路径:
#!/bin/bash
- 如果使用的是Alpine这类默认不带Bash的极小基础镜像,先在Dockerfile中安装Bash:
RUN apk add --no-cache bash
- 在docker-compose.yml的启动命令中,显式调用Bash执行脚本,不要用sh调用:
command: bash /opt/app/zuulStartContainer.sh
改完后原有依赖$SECONDS的逻辑可以直接正常运行,和宿主机行为完全一致。
方案2:改写为POSIX兼容逻辑(无额外依赖,适配所有Shell环境)
如果不想额外安装Bash,可以放弃$SECONDS和Bash专属语法,用Unix时间戳自行计算等待时长,所有标准POSIX Shell都能直接运行,改完的脚本示例如下:
echo "right before second" start_time=$(date +%s) echo "start at timestamp: ${start_time}" echo "right after second" interval=10 max_wait=120 while true; do current_time=$(date +%s) waited_time=$((current_time - start_time)) if [ ${waited_time} -ge ${max_wait} ]; then break fi SuccessMessage=$(grep "successful" "$LOG_FILE" | wc -l) if [ "$SuccessMessage" -gt 0 ]; then echo "Successful" exit 0 fi echo "Waiting... (already waited ${waited_time}s)" sleep ${interval} done echo "Failed to Start" exit 1
注意:该写法不需要依赖Bash,脚本shebang写#!/bin/sh即可,在宿主机和任意Docker容器环境下都能稳定运行。
内容的提问来源于stack exchange,提问作者pja
相关产品推荐
相关产品推荐

