朕喜技术(ZhenxiJS)
2026.09.06
1 分钟阅读

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

版权声明

本文为博主原创文章,遵循 CC BY-NC-SA 4.0 许可协议。 转载请注明出处:http://localhost/blogs/2026-09-06-1611-crlf-entrypoint-no-such-file-or-directory

分享这篇文章