Developer Advocate @docker. Microsoft MVP. Pluralsight Author.
Posts my own.

  My Pluralsight Courses
 
 Old blog 
 Speaking
 Books
 Courses
    http://localhost:2368/content/images/2017/03/docker-london-feb2017.jpg

    Windows, Dockerfiles and the Backtick Backslash Backlash

    Updated! With the SHELL instruction

    Updated! From Docker 1.13 all Dockerfile instructions respect the escape character, see Windows: Honour escape directive fully

    In the Dockerfile spec the backslash is used as an escape character, and also for line continuation. Line continuation is important - each instruction in a Dockerfile creates a new image layer, so you want your instructions to be dense. Spreading them over many lines makes your Dockerfiles easier to read, which means easier to maintain.

    It's not a problem with Linux, where there's no conflict with the backslash character, and you can happily write instructions like this:

    FROM ubuntu  
    COPY template.html /template.html  
    WORKDIR /var/www  
    RUN ["/bin/bash", "-c", \  
         "cat", "/template.html", \
         ">", "/var/www/index.html"]
    

    In Windows, the backslash is the separator in file paths, so we have to escape it in Dockerfiles, otherwise it will be interpreted as a line continuation. File paths then have double backslashes \\, and the single backslash is used for line continuation:

    FROM microsoft/nanoserver  
    COPY template.html c:\\template.html  
    WORKDIR c:\\inetpub\\wwwroot  
    RUN ["powershell", \  
         "cat c:\\template.html", \
         "> c:\\inetpub\\wwwroot\\index.html"]
    

    It looks odd to long-time Windows users, but you can change to a friendlier character using the escape directive, which at the moment only allows backslash or backtick as the escape character. With that, we can rewrite the Windows Dockerfile:

    # escape=`
    
    FROM microsoft/nanoserver  
    COPY template.html c:\template.html  
    WORKDIR c:\inetpub\wwwroot  
    RUN ["powershell", `  
         "cat c:\template.html", `
         "> c:\inetpub\wwwroot\index.html"]
    

    That looks much nicer - our file paths have a single backslash, and the line continuation is a backtick just like with native PowerShell commands.

    The only problem with this Dockerfile is that it won't build

    PS> docker build -t temp .  
    Sending build context to Docker daemon  2.56 kB  
    Step 1/4 : FROM microsoft/nanoserver  
     ---> 105d76d0f40e
    Step 2/4 : COPY template.html c:\template.html  
     ---> 807e39dc2c81
    Removing intermediate container a909e3078e63  
    Step 3/4 : WORKDIR c:\inetpub\wwwroot  
    the working directory 'C:inetpubwwwroot' is invalid, it needs to be an absolute path  
    

    Looks like WORKDIR doesn't respect the changed escape character, and it's stripping out the backslash from the path. In this case we're only using it to create a directory, so let's just change that to a RUN mkdir:

    # escape=`
    
    FROM microsoft/nanoserver  
    COPY template.html c:\template.html  
    RUN mkdir c:\inetpub\wwwroot  
    RUN ["powershell", `  
         "cat c:\template.html", `
         "> c:\inetpub\wwwroot\index.html"]
    

    And now:

    Sending build context to Docker daemon  2.56 kB  
    Step 1/4 : FROM microsoft/nanoserver  
     ---> 105d76d0f40e
    Step 2/4 : COPY template.html c:\template.html  
     ---> Using cache
     ---> 807e39dc2c81
    Step 3/4 : RUN mkdir c:\inetpub\wwwroot  
     ---> Running in e3a513d7c56d
     ---> 5be44746c16f
    Removing intermediate container e3a513d7c56d  
    Step 4/4 : RUN ["powershell",      "cat c:\template.html",      "> c:\inetpub\wwwroot\index.html"]  
     ---> Running in 344d0ca21146
    '["powershell"' is not recognized as an internal or external command,  
    operable program or batch file.  
    

    We're failing on Step 4, which is the multi-line RUN command. That's because I'm using exec form to run PowerShell directly, without a command shell wrapper. In exec mode Docker parses the command and arguments as JSON, and the single backslash is not valid JSON... From the docs:

    Note: In the JSON form, it is necessary to escape backslashes. This is particularly relevant on Windows where the backslash is the path separator. The following line would otherwise be treated as shell form due to not being valid JSON, and fail in an unexpected way: RUN ["c:\windows\system32\tasklist.exe"] The correct syntax for this example is: RUN ["c:\windows\system32\tasklist.exe"]

    So, if you want to keep your Dockerfiles looking Windows-y, use the backtick to escape, watch out for instructions that don't work with it, and stick to shell form for running commands:

    # escape=`
    
    FROM microsoft/nanoserver  
    COPY template.html c:\template.html  
    RUN mkdir c:\inetpub\wwwroot  
    RUN powershell `  
         cat c:\template.html `
         > c:\inetpub\wwwroot\index.html
    

    Alternatively, PowerShell does support forward slashes in commands, so you can stick with the Linux syntax for paths and use the backslash to escape. Your file paths will look odd, but you can work with Dockerfiles without any restrictions:

    FROM microsoft/nanoserver  
    COPY template.html c:/template.html  
    WORKDIR c:/inetpub/wwwroot  
    RUN ["powershell", \  
         "cat c:/template.html", \
         "> c:/inetpub/wwwroot/index.html"]
    

    As Michael Friis from Docker pointed out, I'd missed the best option - combining escape and SHELL

    The SHELL instruction in a Dockerfile specifies the command shell to use for the rest of the build. Using it you can switch to PowerShell instead of cmd and use shell form, so you don't need to escape backslashes, and you can use the backtick for line breaks:

    # escape=`
    
    FROM microsoft/nanoserver  
    SHELL ["powershell","-command"]
    
    COPY template.html c:\template.html  
    RUN mkdir c:\inetpub\wwwroot  
    RUN cat c:\template.html `  
        > c:\inetpub\wwwroot\index.html
    

    Share this article on
    Author image
    Written by Elton Stoneman
    Developer Advocate @docker. Microsoft MVP. Pluralsight Author.