我正在阅读Dockerfile Reference的转义部分。在文档中,有一个示例演示了默认转义字符"\"如何在 Windows 系统中造成问题。
FROM microsoft/nanoserver
COPY testfile.txt c:\
RUN dir c:
结果:
PS C:\John> docker build -t cmd .
将构建上下文发送到 Docker 守护程序 3.072 kB 步骤 1/2 :
从 microsoft/nanoserver ---> 22738ff49c6d
步骤 2/2 : 复制测试文件.txt c:\RUN dir c:
GetFileAttributesEx c:RUN:系统找不到指定的文件。
PS C:\约翰>
根据我的理解,COPY testfile.txt c:\
中的第一个反斜杠将转义第二个反斜杠,命令变为COPY testfile.txt c:
。反斜杠在RUN dir c:
命令中消失,因为它用作转义字符,这是有意义的。但是,我不确定为什么换行符也被转义,因为 COPY 和 RUN 命令合并为一个命令。我不是逃脱字符的专家,我可能会误解这里一些非常基本的东西。你能告诉我在这种情况下如何转义字符吗?提前谢谢。
在 Windows 上使用 escape 指令来避免这些麻烦,例如:
# escape=`
FROM microsoft/nanoserver
COPY testfile.txt c:
RUN dir c:
在您的情况下,第二个斜杠正在转义换行符。因此,两条线一起运行以形成:COPY testfile.txt c:RUN dir c:
。我知道您认为第一个斜杠应该转义第二个斜杠,但根据文档,这不是解析器的行为方式。
好吧,这很痛苦,但我想我现在有一个答案。
TL;DR 我认为对于 RUN 和 CMD 以外的所有指令,使用两次"转义字符"会自行转义。Docker文档似乎已经过时了。
<小时 />完整说明
要从 OP 发布的文档中运行示例,我认为需要切换 docker 守护进程以运行 Windows 容器而不是 Linux 容器。我认为这对于拉取 Windows 映像而不会引起此错误至少是必要的:
ltsc2022: Pulling from windows/nanoserver
no matching manifest for linux/amd64 in the manifest list entries
Docker 文档需要更新,FROM windows/nanoserver
会给你一个错误。因此,我更改了FROM
指令。这是我的测试Dockerfile:
# escape=
FROM mcr.microsoft.com/windows/nanoserver:win10-21h1-preview
COPY testfile.txt c:\
RUN dir c:
COPY \subdir\subfile.txt c:\newdir\
RUN dir c: /w
RUN dir /w c:subdir\
RUN type c:testfile.txt
这行得通!需要注意的几点:
- 我无法重现文档错误,其中:
第二行末尾的第二个 \ [即我的第一个 COPY 指令末尾的
] 将被解释为换行符的转义,而不是从第一行 \ 转义的目标。我认为文档已过时。
我想他们终于纠正了这种奇怪的行为。
- 文档说:
转义不在 RUN 命令中执行,行尾除外。
这应该对 RUN 或 CMD 指令有效。RUN 指令可以以 2 种形式(CMD 以 3 种形式(、shell 或 exec 形式运行。在 shell 形式中,它会从字面上读,除了在行尾,它会通过将
解释为转义字符来给你带来麻烦,这将在下一条指令之前转义任何空格。因此:
RUN dir c:
# breaks the code, because it will escape white space
# and add the next lines to this instruction. That is:
# RUN dir c:RUN dir...
RUN dir c:\
# also doesn't work, because then it runs as `cmd /S /C dir c:\
# which is invalid syntax. It must be `c:` instead
有趣的是,这 2 条指令会起作用,但我无法解释为什么第一个有效:
RUN dir c:newdir\
# works! But why does this work and `RUN dir c:\` doesn't?
RUN dir c: /w
# works because it doesn't end in `c://`
无论如何,在这些情况下,最好的办法是以执行形式运行这些指令。当采用 exec 形式时,参数被解析为 JSON,因此必须始终包含在"
中,并且所有都需要转义。
RUN ["cmd", "/C", "dir", "c:\"]
# works