Files
docker_practice/image/dockerfile/shell.md
2026-01-30 16:48:39 -08:00

142 lines
3.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 指令](../../image/build.md)执行命令
- [Dockerfile 最佳实践](../../appendix/best_practices.md)错误处理与调试