首页/云/Docker 容器速查/RUN 两种形式的语义差异
镜像与构建107 条

RUN 两种形式的语义差异

shell 形式实际执行 /bin/sh -c "命令串",exec 形式直接执行可执行文件;默认 /bin/sh 往往不是 bash,语法差异要留心。

Docker 容器速查云更新于 2026-10-13

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
切换 shellSHELL ["/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 是否参与了解析。

易错点

  • 在 musl 系(如 Alpine)镜像里写 bash 语法,构建直接报语法错误,根源是默认 shell 不是 bash
  • exec 形式里写通配或管道(如指定 *.txt),这些字符不会被展开,行为与预期不符
  • exec 形式误写成单个字符串而不是 JSON 数组,会被当成可执行文件名,报找不到命令
  • 把 SHELL 切到 bash 却没在镜像里安装 bash,后续所有指令一起失败
  • 把需要 shell 展开的命令塞进 exec 形式,变量不会被替换,问题在运行阶段才暴露,定位成本更高

数据来源与参考

  • Docker 官方文档:Dockerfile RUN(docs.docker.com)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌