This commit is contained in:
Baohua Yang
2026-02-09 12:56:12 -08:00
parent 63377d0431
commit b44c9acd6c
228 changed files with 326 additions and 271 deletions

154
07_dockerfile/7.15_shell.md Normal file
View File

@@ -0,0 +1,154 @@
## 7.15 SHELL 指令
### 基本语法
具体内容如下
```docker
SHELL ["executable", "parameters"]
```
`SHELL` 指令允许覆盖 Docker 默认的 shell
- **Linux 默认**`["/bin/sh", "-c"]`
- **Windows 默认**`["cmd", "/S", "/C"]`
该指令会影响后续的 `RUN`, `CMD`, `ENTRYPOINT` 指令当它们使用 shell 格式时
---
### 为什么要用 SHELL 指令
#### 1. 使用 bash 特性
默认的 `/bin/sh`通常是 dash alpine ash功能有限如果你需要使用 bash 的特有功能如数组`{}` 扩展`pipefail` 可以切换 shell
```docker
FROM ubuntu:24.04
## 切换到 bash
SHELL ["/bin/bash", "-c"]
## 现在可以使用 bash 特性了
RUN echo {a..z}
```
#### 2. 增强错误处理pipefail
默认情况下管道命令 `cmd1 | cmd2` 只要 `cmd2` 成功整个指令就视为成功这可能掩盖构建错误
```docker
## ❌ 这里的 wget 失败了,但构建继续(因为 tar 成功了)
RUN wget -O - https://invalid-url | tar xz
```
使用 `SHELL` 启用 `pipefail`
```docker
## ✅ 启用 pipefail
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
## 如果 wget 失败,整个 RUN 就会失败
RUN wget -O - https://invalid-url | tar xz
```
#### 3. Windows 环境
Windows 容器中经常需要在 `cmd` `powershell` 之间切换
```docker
FROM mcr.microsoft.com/windows/servercore:ltsc2022
## 默认是 cmd
RUN echo Default shell is cmd
## 切换到 powershell
SHELL ["powershell", "-command"]
RUN Write-Host "Hello from PowerShell"
## 切回 cmd
SHELL ["cmd", "/S", "/C"]
```
---
### 作用范围
`SHELL` 指令可以出现多次每次只影响其后的指令
```docker
FROM ubuntu:24.04
## 使用默认 sh
RUN echo "Using sh"
SHELL ["/bin/bash", "-c"]
## 使用 bash
RUN echo "Using bash"
SHELL ["/bin/sh", "-c"]
## 回到 sh
RUN echo "Using sh again"
```
---
### 对其他指令的影响
`SHELL` 影响的是所有使用 **shell 格式** 的指令
| 指令格式 | 是否受 SHELL 影响 |
|---------|-------------------|
| `RUN command` | |
| `RUN ["exec", "param"]` | |
| `CMD command` | |
| `CMD ["exec", "param"]` | |
| `ENTRYPOINT command` | |
| `ENTRYPOINT ["exec", "param"]` | |
---
### 最佳实践
#### 1. 推荐开启 pipefail
对于使用 bash 的镜像强烈建议开启 `pipefail`以确保构建过程中的错误能被及时捕获
```docker
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
```
#### 2. 明确意图
如果由于脚本需求必须更改 shell最好在 Dockerfile 中显式声明而不是依赖默认行为
#### 3. 尽量保持一致
避免在 Dockerfile 中频繁切换 SHELL这会使构建过程难以理解和调试尽量在头部定义一次即可
---
### 本章小结
| 要点 | 说明 |
|------|------|
| **作用** | 更改 RUN/CMD/ENTRYPOINT 的默认 shell |
| **Linux 默认** | `["/bin/sh", "-c"]` |
| **Windows 默认** | `["cmd", "/S", "/C"]` |
| **推荐用法** | `SHELL ["/bin/bash", "-o", "pipefail", "-c"]` |
| **影响范围** | 后续所有使用 shell 格式的指令 |
### 延伸阅读
- [RUN 指令](../../04_image/4.5_build.md)执行命令
- [Dockerfile 最佳实践](../../16_appendix/16.1_best_practices.md)错误处理与调试