# SHELL

```
SHELL ["executable", "parameters"]
```

**SHELL指令**被用于覆盖**shell**形式的命令的默认**shell**。在Linux上的默认**shell**&#x662F;**\["/bin/sh", "-c"]**, 在**windows**上&#x662F;**\["cmd", "/S", "/C"]**。在**Dockerfile**中**SHELL指令**必须是**JSON**形式。

**SHELL指令**在**Windows**上特别有用，**windows**有两个常用的但是完全不同的原生**shell**：**cmd**和**powershell**，以及包括一个备用的**sh**。

**SHELL指令**可以出现多次。每一个**SHELL指令**可以覆盖先前的**SHELL指令**，并影响后续的指令。例如：

```
FROM microsoft/windowsservercore

# Executed as cmd /S /C echo default
RUN echo default

# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default

# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello

# Executed as cmd /S /C echo hello
SHELL ["cmd", "/S", "/C"]
RUN echo hello
```

当**RUN**，**CMD**和**ENTRYPOINT指令**使用**shell**形式的命令时，都会受到**SHELL指令**的影响。

以下示例是**Windows**上常见的查找模式，可以通过使用**SHELL指令**进行简化：

```
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
```

被**docker**调用的命令执行时将是下面这个样子：

```
cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
```

上面这种方式并不高效，原因有两个：

1. 这里有一个不必要的**cmd.exe**命令处理器（**aka shell**）被调用。
2. 每一个**shell**形式的**RUN指令**需要一个额外的**powershell -command**作为命令前缀。

为了提高效率，可以采用两种机制之一。一种是使用**RUN**命令的**JSON**形式，如：

```
RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]
```

虽然**JSON**形式比较清晰，不会使用不必要的**cmd.exe**，但通过双引号和转义使得写法非常啰嗦。替代方案是使用**SHELL指令**和**shell**形式，为**Windows**用户创建一种更自然的语法，特别与**解析器指令**结合使用时：

```
# escape=`

FROM microsoft/nanoserver
SHELL ["powershell","-command"]
RUN New-Item -ItemType Directory C:\Example
ADD Execute-MyCmdlet.ps1 c:\example\
RUN c:\example\Execute-MyCmdlet -sample 'hello world'
```

运行结果：

```
PS E:\docker\build\shell> docker build -t shell .
Sending build context to Docker daemon 4.096 kB
Step 1/5 : FROM microsoft/nanoserver
 ---> 22738ff49c6d
Step 2/5 : SHELL powershell -command
 ---> Running in 6fcdb6855ae2
 ---> 6331462d4300
Removing intermediate container 6fcdb6855ae2
Step 3/5 : RUN New-Item -ItemType Directory C:\Example
 ---> Running in d0eef8386e97


    Directory: C:\


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       10/28/2016  11:26 AM                Example


 ---> 3f2fbf1395d9
Removing intermediate container d0eef8386e97
Step 4/5 : ADD Execute-MyCmdlet.ps1 c:\example\
 ---> a955b2621c31
Removing intermediate container b825593d39fc
Step 5/5 : RUN c:\example\Execute-MyCmdlet 'hello world'
 ---> Running in be6d8e63fe75
hello world
 ---> 8e559e9bf424
Removing intermediate container be6d8e63fe75
Successfully built 8e559e9bf424
PS E:\docker\build\shell>
```

**SHELL指令**也可以被用于修改**shell**的操作。例如，在**windows**上使用**SHELL CMD /S /C /V:ON|OFF**可以修改延迟环境变量扩展语义。

**SHELL**特性在**Docker1.12**被添加。
