如何替换匹配项中的文本(但不是每个匹配项)?

如何替换匹配项中的文本(但不是每个匹配项)?

我想AllowOverride None从有路径的组中进行替换/var/www/。我正在使用 sed 来执行此操作,但它会替换所有匹配项。

Apache2.conf在运行脚本之前

<Directory />
    Options FollowSymLinks
    AllowOverride None
    Require all denied
</Directory>

<Directory /usr/share>
    AllowOverride None
    Require all granted
</Directory>

<Directory /var/www/>
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

Apache2.conf运行脚本后

<Directory />
    Options FollowSymLinks
    AllowOverride All
    Require all denied
</Directory>

<Directory /usr/share>
    AllowOverride All
    Require all granted
</Directory>

<Directory /var/www/>
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

脚本文件

#!/bin/bash

sed "s/AllowOverride None/AllowOverride All/g" apache2.conf

我的问题是:我如何告诉 sed 替换它的位置/var/www/

答案1

您可以使用以下 Perl oneliner 来实现此目的:

perl -0777 -pe 's{(<Directory\s/var/www/.*?AllowOverride\s)None(.*?</Directory>)}{$1All$2}gs' /tmp/file

这里-0777flag 将行分隔符更改为 undef,因此 perl 会将文件作为一行读取(这对于大文件可能是一个问题)。

-p循环文件行并打印它们, -e运行脚本, /tmp/file您的配置文件

s{(<Directory\s/var/www/.*?AllowOverride\s)None(.*?</Directory>)}{$1All$2}gs是与 /var/www 匹配目录节的 2 部分的正则表达式,并且基本上将 None 替换为 All。请注意,在 Perl 中,您几乎可以使用任何符号作为正则表达式分隔符,在本例中我使用{}而不是//.

答案2

一种方法sed是:

sed -E '/<Directory \/var\/www\/>/,/<\/Directory>/{
       s/AllowOverride None/AllowOverride All/; }' infile

这更新/更改了AllowOverride NoneAllowOverride All仅当介于两者之间时<Directory /var/www/>&</Directory>(我们用反斜杠转义斜杠,这是因为斜杠对于 sed 命令来说是特殊字符)。

相关内容