技巧51 用perl -p -i -e替换文本
使用Dockerfile构建镜像时,在多个文件间替换文本的特定内容的需求并不罕见。有多种方案可以解决这一问题,但是我们这里要介绍的是一个有点儿不太常见的方式,用在Dockerfile里特别方便。
问题
想要在构建期间修改多个文件里的特定行。
解决方案
使用 perl -p -i -e
。
我们偏好这个命令有如下原因。
- 与
sed -i
不同(该命令具有类似的语法和效果),这一命令天然支持处理多个文件,即便遇到的问题是修改其中一个文件。这意味着可以在一个目录下加上'*'
通配符来执行该命令,便不用再担心在包的后续版本里添加目录时它突然不工作了。 - 和
sed
一样,搜索和替换命令中的正斜杠可以使用其他字符替换。 - 它还很容易记忆(我们不妨称之为
perl pie
命令)。
注意
本技巧假定读者对正则表达式有所了解。如果对正则表达式不熟悉,有很多网站会很有帮助。
下面是该命令的一个典型示例:
perl -p -i -e 's/127\.0\.0\.1/0.0.0.0/g' *
在这条命令里, -p
标志要求Perl循环处理看到的所有行, -i
标志要求Perl原地更新匹配的行内容,而 -e
标志则要求Perl把传入的字符串当作一个Perl程序处理。 s
是Perl的一个指令,用来搜索和替换输入里匹配的字符串。这里的 127.0.0.1
会被替换成 0.0.0.0
。 g
修饰符则确保所有匹配都被更新,而不只是任何给定行里的第一个匹配。最后,星号( *
)会使这一文件夹下的所有文件都被更新。
对Docker容器而言,上述命令完成的不过是一个很平常的操作。它会在使用一个地址来监听时,将标准的本地主机IP地址( 127.0.0.1
)替换成一个指示“任意”IPv4地址( 0.0.0.0
)的地址。许多应用会通过仅监听本地主机地址限制成只有该IP地址才能访问,而通常用户会想要在它们的配置文件里将这一配置修改成“任意”地址,因为从宿主机上访问这些应用时,容器就变成了一台外部主机。
提示
如果一个Docker容器里的应用,即使端口是打开的,用户仍然无法从宿主机上访问,不妨尝试一下在应用的配置文件里把监听的地址修改为 0.0.0.0
,并重启应用。这可能是应用拒绝访问所致,因为用户不是从本地主机访问它。在运行镜像时加上 --net=host
(后面技巧109会介绍到)可以帮助验证这一猜测。
perl -p -i -e
(和 sed
)还有另外一个很不错的功能,那便是:如果有麻烦的字符转义问题,用户可以使用其他字符替换正斜杠。下面是一个来自本书作者编写的脚本的真实示例,它在默认的Apache站点文件里添加了一些指令。
这条尴尬的命令
perl -p -i -e 's/\/usr\/share\/www/\/var\/www\/html/g' /etc/apache2/*
就变成了
perl -p -i -e 's@/usr/share/www@/var/www/html/@g' /etc/apache2/*
在极少数情况下,用户要匹配或替换 /
和 @
字符,可以尝试其他字符,如 |
或 #
。
讨论
本技巧是那些可以同时应用在Docker世界内外的技巧之一。它是一个有用的工具,你不妨将它放到自己的工具箱里。
我们认为本技巧非常有用的原因是它在Dockerfile之外也有广泛的应用,并且要记住它也是一件十分容易办到的事情,这真的是小菜一碟,我可没开玩笑。