RUN 的两种形式
shell 形式把命令交给 /bin/sh -c 执行,支持变量展开、管道与重定向;exec 形式用 JSON 数组直接执行可执行文件,不经 shell。要注意默认的 /bin/sh 在不少基础镜像里是 dash 或 ash,语法差异必须先确认。
基本信息
| shell 形式 | RUN echo $HOME,变量与通配由 shell 展开 |
|---|---|
| exec 形式 | RUN ["/bin/echo", "$HOME"],参数原样传递 |
| 默认 shell | /bin/sh,Debian 系通常是 dash,Alpine 是 ash |
| 切换 shell | SHELL ["/bin/bash", "-c"] |
| 作用范围 | SHELL 影响其后所有 shell 形式的指令与启动命令 |
典型使用场景
- 需要管道、重定向、条件判断时用 shell 形式
- 需要精确控制参数、避免被 shell 二次解析时用 exec 形式
- 排查构建里 bash 语法报错:先确认镜像里的 /bin/sh 到底是什么
- 给 Alpine 基础镜像写脚本时按 ash 兼容性调整语法
- 统一 SHELL 让构建脚本与本地脚本行为一致
- 排查命令找不到:exec 形式不经 shell,路径与参数都要写全
示例
示例
# shell 形式:支持管道、变量与重定向
RUN ps aux | grep nginx || true
RUN set -eux; apt-get update; apt-get install -y --no-install-recommends curl
# exec 形式:不经 shell,参数原样传递
RUN ["/usr/bin/env", "bash", "-lc", "echo $PATH"]
# 需要 bash 特性时改默认 shell(影响后续所有 shell 形式指令)
SHELL ["/bin/bash", "-c"]两种形式的差别
| 方面 | shell 形式 | exec 形式 |
|---|---|---|
| 执行方式 | 交给 /bin/sh -c 执行命令串 | 直接执行可执行文件 |
| 变量展开 | 由 shell 完成 | 字符串原样传给程序 |
| 管道与重定向 | 支持 | 不支持,需要自己调用 shell |
| 受基础镜像影响 | 是(dash、ash 差异明显) | 否 |
| 常见用途 | 安装、编译等组合命令 | 精确调用某一个二进制 |
在 dash 或 ash 为基础镜像的构建里写 bash 专有语法会报语法错误,报错行号经常让人看不出问题所在,先确认默认 shell 能省很多时间。
exec 形式不享受 shell 的帮助:命令路径、参数与环境都要写全,写成相对路径时容易报找不到命令。
SHELL 是全局开关,改动它会影响后续所有 shell 形式的指令与启动命令,改之前确认基础镜像里确实装了 bash。
构建日志里每条指令都带执行形式,出现 /bin/sh -c 前缀说明走的是 shell 形式,据此能快速判断默认 shell 是否参与了解析。