Dockerfile RUN命令跨机器执行异常及脚本解释器疑问
Docker构建镜像报错问题解答
问题背景
Dockerfile配置片段:
FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu20.04 ... RUN ./my_script.sh
脚本my_script.sh首行声明为#!/bin/bash。同事在Linux Ubuntu 22.04环境下可正常构建镜像,但在Windows 11的WSL2(Ubuntu 22.04)环境下执行docker compose build时,出现如下错误:
ERROR [application 10/11] RUN ./my_script.sh 0.426 /bin/sh: 1: ./my_script.sh: not found
疑问解答
1. 容器操作系统一致,RUN命令在容器内执行,为何不同机器表现不同?
核心原因是Windows与Linux的换行符差异:
- Windows系统默认使用
CRLF(\r\n)作为换行符,Linux则使用LF(\n)。如果你的脚本是在Windows环境下编辑的,换行符会是CRLF,当通过WSL2挂载到Docker构建上下文并复制到容器后,脚本首行的#!/bin/bash会被解析为#!/bin/bash\r,系统找不到名为/bin/bash\r的解释器,从而抛出"not found"错误。 - 同事直接在Linux环境下编辑脚本,换行符为LF,复制到容器后解释器路径正常,因此可以顺利执行。
- 另外需排除文件权限问题:若脚本无执行权限,报错会是"Permission denied",与当前报错不符,因此换行符问题是主要诱因。
2. 脚本已声明/bin/bash,为何错误提示使用/bin/sh?
- Docker的
RUN命令默认使用/bin/sh作为执行shell。当脚本的解释器路径因换行符问题失效时,系统会 fallback 到默认的/bin/sh尝试执行脚本,但此时脚本的有效解释器路径不存在,所以/bin/sh会抛出"not found"的错误提示(该信息有一定误导性,实际是找不到有效解释器导致脚本无法执行)。 - 可以通过两种方式规避:一是显式指定用bash执行脚本,将
RUN ./my_script.sh改为RUN bash ./my_script.sh;二是在Dockerfile开头添加SHELL ["/bin/bash", "-c"],让后续所有RUN命令默认使用bash执行。
解决方法
- 转换脚本换行符:在编辑器(如VS Code)右下角将换行符切换为LF,或在WSL2终端执行
dos2unix my_script.sh命令完成转换。 - 确保脚本可执行:在WSL2终端执行
chmod +x my_script.sh,或在Dockerfile中RUN ./my_script.sh之前添加RUN chmod +x ./my_script.sh。
内容的提问来源于stack exchange,提问作者Jakub Małecki
相关产品推荐
相关产品推荐

