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
相关推荐
爱瑞瑞14 分钟前
云原生学习笔记(七) Docker 实战:使用 Docker 快速构建 Oracle 12c 容器
docker·oracle
exe4522 小时前
使用docker中的ollama
运维·docker·容器
IT成长日记3 小时前
【Docker基础】Docker核心概念:命名空间(Namespace)之NET详解
运维·docker·容器·namespace·net
雨师@3 小时前
ATM 模拟器 Golang 程序--示例
开发语言·后端·golang
你怎么知道我是队长8 小时前
GO语言---匿名函数
开发语言·后端·golang
早起鸟儿13 小时前
docker-Dockerfile 配置
java·linux·运维·docker
虚妄狼13 小时前
【Docker Desktop】Windows11安装 Docker Desktop
运维·docker·容器
不被定义的程序猿13 小时前
Golang 在 Linux 平台上的并发控制
开发语言·后端·golang
IT成长日记14 小时前
【Docker基础】Docker核心概念:命名空间(Namespace)与资源隔离联系
运维·docker·namespace·资源隔离·命令空间
ifanatic14 小时前
[每周一更]-(第147期):使用 Go 语言实现 JSON Web Token (JWT)
前端·golang·json