技巧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.0g 修饰符则确保所有匹配都被更新,而不只是任何给定行里的第一个匹配。最后,星号( * )会使这一文件夹下的所有文件都被更新。

对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之外也有广泛的应用,并且要记住它也是一件十分容易办到的事情,这真的是小菜一碟,我可没开玩笑。

results matching ""

    No results matching ""