Dockerfile的ADD指令对中括号转义

文章目录

环境

  • RHEL 9.3
  • Docker Community 24.0.7

背景

在Docker官方文档 https://docs.docker.com/engine/reference/builder/#add 里有这么一段话:

When adding files or directories that contain special characters (such as [ and ]), you need to escape those paths following the Golang rules to prevent them from being treated as a matching pattern. For example, to add a file named arr[0].txt, use the following;

powershell 复制代码
ADD arr[[]0].txt /mydir/

翻译成中文就是:如果添加的文件或目录包含特殊字符(比如 [] ),需要按照Golang的规则进行转义,以避免被当成匹配模式。

例如,想要添加文件 arr[0].txt ,需要转义为 arr[[]0].txt

我测试了一下,确实是这样的,但是这种转义方法实在让人有点费解:

  • 源文件名: arr[0].txt
  • 转义后的文件名: arr[[]0].txt

Docker文档里没说清楚到底是怎么转义的,为此我查了一下Golang的文档,才明白是怎么回事。

分析

在Dockerfile里, ADD 指令的 <src> 参数里可以包含通配符。比如, * 表示"通配任意多个字符", ? 表示"通配任意一个字符"。

所以,显然Docker会采用匹配模式的方式来添加文件和目录。我们知道,Docker是用Go语言开发的。查看Go语言的官方文档,其 filepath.Match() 方法定义如下:

go 复制代码
func Match(pattern, name string) (matched bool, err error)

其第一个参数"pattern"的定义如下:

powershell 复制代码
pattern:
	{ term }
term:
	'*'         matches any sequence of non-Separator characters
	'?'         matches any single non-Separator character
	'[' [ '^' ] { character-range } ']'
	            character class (must be non-empty)
	c           matches character c (c != '*', '?', '\\', '[')
	'\\' c      matches character c

character-range:
	c           matches character c (c != '\\', '-', ']')
	'\\' c      matches character c
	lo '-' hi   matches character c for lo <= c <= hi

可见, [] 是特殊字符, [] 可以包含一个范围,比如 [1-5] 表示1到5。

下面是一个完整的Go示例:

go 复制代码
package main

import (
  "fmt"
  "path/filepath"
)

func main() {
  fmt.Println(filepath.Match("/home/catch[1-5]", "/home/catch2"))
  fmt.Println(filepath.Match("/home/catch[1-5]", "/home/catch8"))
}

运行结果如下:

powershell 复制代码
true <nil>
false <nil>

可见,因为 2[1-5] 范围里,所以返回true,而 8 不在 [1-5] 范围里,所以返回false。

现在,回到Dockerfile。已知源文件名为 arr[0].txt ,如果直接写成:

powershell 复制代码
ADD arr[0].txt dir1/

考一考:实际匹配的源文件名是什么?

答:因为 [] 被Docker当作一个范围,而范围里只有一个数字 1 ,因此只匹配了 1 ,也就是说,实际匹配的源文件名为 arr0.txt

如果有兴趣,可以动手试一试,验证一下结果。

显然,需要对 [] 转义,那么该如何转义呢?

答案:只需用 [][ 括起来。

因为 [] 被Docker当作一个范围,而范围里只有一个字符 [ ,因此只匹配了 [ 。后面的内容不需要再转义了。

因此,整个源文件名转义为 arr[[]0].txt 。这就是文章开头提到的,想要添加文件 arr[0].txt ,需要转义为 arr[[]0].txt

参考

  • https://docs.docker.com/engine/reference/builder/#add
  • https://pkg.go.dev/path/filepath#Match
相关推荐
想学习java初学者40 分钟前
Docker compose部署elasticsearch(单机版)
运维·docker·容器
微刻时光2 小时前
Docker部署Nginx
运维·nginx·docker·容器·经验
@东辰3 小时前
【golang-技巧】-自定义k8s-operator-by kubebuilder
开发语言·golang·kubernetes
陈小肚3 小时前
k8s 1.28.2 集群部署 docker registry 接入 MinIO 存储
docker·容器·kubernetes
A陈雷3 小时前
springboot整合elasticsearch,并使用docker desktop运行elasticsearch镜像容器遇到的问题。
spring boot·elasticsearch·docker
小扳3 小时前
Docker 篇-Docker 详细安装、了解和使用 Docker 核心功能(数据卷、自定义镜像 Dockerfile、网络)
运维·spring boot·后端·mysql·spring cloud·docker·容器
@东辰4 小时前
【golang-技巧】- 定时任务 - cron
开发语言·golang·cron
jerry60910 小时前
7天用Go从零实现分布式缓存GeeCache(改进)(未完待续)
分布式·缓存·golang
杜杜的man11 小时前
【go从零单排】Closing Channels通道关闭、Range over Channels
开发语言·后端·golang
南猿北者12 小时前
docker Network(网络)
网络·docker·容器