Docker entrypoint 报错 "exec user process caused: no such file or directory":CRLF 行尾符让 shebang 解释器路径失效
日期:2026-09-06 | 技术栈:Docker, docker compose, Bash, Linux shebang, CRLF/LF, dos2unix, sed, tr, gitattributes | 关键词:exec user process caused no such file or directory, CRLF line terminators, Docker entrypoint 启动秒退, standard_init_linux.go, /bin/bash\r not found, Windows 编辑 shell 脚本报错, dos2unix 转换脚本, git core.autocrlf
一、问题背景
在 Windows 上用编辑器编写了一个 entrypoint.sh 脚本并提交到 Git 仓库。构建 Docker 镜像后,用 docker compose up 启动容器,容器瞬间退出。查看日志,只有一行令人困惑的报错:
standard_init_linux.go:xxx: exec user process caused: no such file or directory
更诡异的是:脚本 /entrypoint.sh 确实存在、内容看着完全正常、权限也正确(-rwxr-xr-x)。那 Docker 为什么会说 "no such file or directory"?
二、复现步骤
# 1. 准备项目(entrypoint.sh 用 CRLF 行尾符)
cd scenario/2026-09-06-1600/
docker compose up -d --build
# 2. 观察容器状态 —— 启动即秒退
docker ps -a | grep crlf-bug
# → Exited (255)
# 3. 查看日志 —— 核心报错
docker compose logs app
# → crlf-bug | exec /entrypoint.sh: no such file or directory
# 4. 确认文件确实存在(排除"文件不存在"的误判)
docker run --rm --entrypoint ls crlf-bug -la /entrypoint.sh
# → -rwxr-xr-x 1 root root 321 ... /entrypoint.sh
# 5. 查看文件字节级内容 —— 发现问题
file entrypoint.sh
# → ... with CRLF line terminators
head -1 entrypoint.sh | od -c
# → # ! / b i n / b a s h \r \n
# 注意!/bin/bash 后面是 \r\n
cat -A entrypoint.sh | head -3
# → #!/bin/bash^M$
# → ^M$
# → # This entrypoint...^M$
关键诊断输出
直接在宿主机执行也会失败:
./entrypoint.sh
# → sh: 1: ./entrypoint.sh: not found (exit 127)
bash entrypoint.sh # 绕过 shebang 显式执行
# → entrypoint.sh: line 2: $'\r': command not found
# → entrypoint.sh: line 5: $'\r': command not found
# → entrypoint.sh: line 15: syntax error: unexpected end of file
三、根本原因
Linux 执行带 shebang 的脚本时,内核会读取第一行(如 #!/bin/bash),然后找该路径对应的可执行文件作为解释器来运行脚本。
Windows 保存的文件默认用 CRLF(\r\n)行尾符。如果第一行 shebang 实际是:
#!/bin/bash\r
内核解析出的解释器路径就是 /bin/bash\r(带一个不可见的回车符 \r,ASCII 0x0D)。这个路径在 Linux 上不存在,所以内核报:
exec user process caused: no such file or directory
报错为什么误导人?
- 报错信息指向「找不到」,让人第一时间去检查脚本文件是否存在 —— 但它确实存在!
- 真正找不到的是 shebang 里指定的解释器路径,而
\r是不可见字符,肉眼根本看不出来。 - 这类似于
echo输出hello\r后光标回到行首,屏幕上看起来内容正常。
即使绕过 shebang 用 bash script.sh 显式执行,CRLF 的 \r 仍会导致问题:每行末尾的 \r 被 shell 当作命令行的一部分,出现 $'\r': command not found 或语法错误。
四、解决办法
方案 1:dos2unix(最推荐)
dos2unix entrypoint.sh
# 或在没有 dos2unix 的宿主上通过容器执行:
docker run --rm -v "$(pwd):/work" --entrypoint sh <已含dos2unix的镜像> -c "dos2unix /work/entrypoint.sh"
方案 2:sed 删除行尾 CR
sed -i 's/\r$//' entrypoint.sh
方案 3:tr 删除所有 CR
tr -d '\r' < entrypoint.sh > entrypoint.tmp && mv entrypoint.tmp entrypoint.sh
方案 4(预防,从源头杜绝):.gitattributes + git core.autocrlf
在仓库根目录创建 .gitattributes:
# 所有 shell 脚本统一 LF 行尾符
*.sh text eol=lf
# 或全局策略
* text=auto
设置 git 行为:
git config --global core.autocrlf input # Linux/macOS 推荐
# Windows 开发者可将 autocrlf 设为 true,但必须配合 .gitattributes 防止 .sh 被转成 CRLF
五、验证结果
修复后重新构建并启动容器:
docker compose up -d --build
docker ps -a | grep crlf-bug
# → Up(不再 Exited)
docker compose logs app
# → Starting application...
# → App starting with config:
三种修复方法(dos2unix / sed / tr)在本实验环境中逐一验证均通过。
六、经验与避坑
1. 什么时候会遇到这个坑?
- 在 Windows(记事本、VS Code、Notepad++ 等)上创建/编辑 shell 脚本并提交到 Git
- 从 Windows 服务器 / FTP 下载的 shell 脚本直接放入 Docker 镜像
- 仓库缺少
.gitattributes行尾符控制 - 文件经 Windows 工具链处理后行尾符发生变化
2. 快速自查清单
# ① file 命令直接看行尾符
file entrypoint.sh
# 输出含 "with CRLF line terminators" → 是 CRLF
# ② od 看第一行字节
head -1 script.sh | od -c
# 看末尾是否有 \r
# ③ cat -A 看隐藏字符(^M = CR)
cat -A script.sh | head -5
3. 修复后立即用 git 确认
# 修复并确认 git 不会重新引入 CRLF
git config core.autocrlf input
git add entrypoint.sh
git status # 确认没有再次被改动
4. Dockerfile 层的额外防御
# 在 Dockerfile 中做防御性转换
RUN sed -i 's/\r$//' /entrypoint.sh
# 或确保镜像内装了 dos2unix 并执行
5. 核心教训
- 报错信息可能具有误导性,别被表象迷惑。报 "no such file" 时,排查的不只是文件是否存在,还要检查解释器路径和文件内容中的不可见字符。
- 提交脚本到仓库前,用
file或cat -A确认行尾符。 - 跨平台协作时,
gitattributes是必备的工程规范,不只是可选项。 - Linux/容器环境对 CRLF 高度敏感,因为 Linux 只认
\n(LF),\r会被当作真实字符参与命令解析。
6. 命令速查
# 诊断
file script.sh | grep CRLF
cat -A script.sh
head -1 script.sh | od -c
# 修复(任选其一)
dos2unix script.sh
sed -i 's/\r$//' script.sh
tr -d '\r' < script.sh > tmp && mv tmp script.sh
# 预防
echo "*.sh text eol=lf" >> .gitattributes
git config core.autocrlf input
