SHELL ["executable", "parameters"]
SHELL instruction allows the default shell used for the shell form of commands to be overridden. The default shell on Linux is
["/bin/sh", "-c"], and on Windows is
["cmd", "/S", "/C"]. The
SHELL instruction must be written in JSON form in a Dockerfile.
SHELL instruction is particularly useful on Windows where there are two commonly used and quite different native shells: cmd and powershell, as well as alternate shells available including sh.
SHELL instruction can appear multiple times. Each
SHELL instruction overrides all previous
SHELL instructions, and affects all subsequent instructions. For example:
FROM 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
The following instructions can be affected by the
SHELL instruction when the shell form of them is used in a Dockerfile:
The following example is a common pattern found on Windows which can be streamlined by using the
... RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt" ...
The command invoked by docker will be:
cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
This is inefficient for two reasons. First, there is an un-necessary cmd.exe command processor (aka shell) being invoked. Second, each
RUN instruction in the shell form requires an extra powershell -command prefixing the command.
To make this more efficient, one of two mechanisms can be employed. One is to use the JSON form of the
RUN command such as:
... RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""] ...
While the JSON form is unambiguous and does not use the un-necessary cmd.exe, it does require more verbosity through double-quoting and escaping. The alternate mechanism is to use the
SHELL instruction and the shell form, making a more natural syntax for Windows users, especially when combined with the escape parser directive:
# escape=` FROM windowsservercore 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 3.584 kB Step 1 : FROM windowsservercore ---> 5bc36a335344 Step 2 : SHELL powershell -command ---> Running in 87d7a64c9751 ---> 4327358436c1 Removing intermediate container 87d7a64c9751 Step 3 : RUN New-Item -ItemType Directory C:\Example ---> Running in 3e6ba16b8df9 Directory: C:\ Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 6/2/2016 2:59 PM Example ---> 1f1dfdcec085 Removing intermediate container 3e6ba16b8df9 Step 4 : ADD Execute-MyCmdlet.ps1 c:\example\ ---> 6770b4c17f29 Removing intermediate container b139e34291dc Step 5 : RUN c:\example\Execute-MyCmdlet -sample 'hello world' ---> Running in abdcf50dfd1f Hello from Execute-MyCmdlet.ps1 - passed hello world ---> ba0e25255fda Removing intermediate container abdcf50dfd1f Successfully built ba0e25255fda PS E:\docker\build\shell>
SHELL instruction could also be used to modify the way in which a shell operates. For example, using
SHELL cmd /S /C /V:ON|OFF on Windows, delayed environment variable expansion semantics could be modified.
SHELL instruction can also be used on Linux should an alternate shell be required such zsh, csh, tcsh and others.
SHELL feature was added in Docker 1.12.