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
相关推荐
cch89181 分钟前
PHP vs Go:Web开发选谁更胜一筹?
前端·golang·php
想搞艺术的程序员30 分钟前
Go map 核心黑魔法:tophash 标记位的极致复用与性能跃升
golang·源码分析·性能
会飞的大可31 分钟前
Docker容器项目无法访问MySQL的解决策略
mysql·docker·容器
eRTE XFUN2 小时前
Redis 设置密码(配置文件、docker容器、命令行3种场景)
数据库·redis·docker
万象.3 小时前
Docker网络原理
网络·docker·容器
呆萌很3 小时前
【GO】函数创建和使用
golang
春日见3 小时前
从底层思维3分钟彻底弄清卷积神经网络CNN
人工智能·深度学习·神经网络·计算机视觉·docker·cnn·计算机外设
wudl55663 小时前
MySQL 8.0.42 Docker 开发部署手册
数据库·mysql·docker
大新新大浩浩4 小时前
Deerflow部署-X86架构-在ubuntu2204操作系统上使用docker模式部署
docker·容器·架构
魔都吴所谓4 小时前
【Linux】Ubuntu22.04 Docker+四大数据库(挂载本地)一键安装脚本
linux·数据库·docker