Regex 在Perl中,在某个特定匹配下编辑/匹配字符串n行?

Regex 在Perl中,在某个特定匹配下编辑/匹配字符串n行?,regex,perl,Regex,Perl,嗨,最近我发布了一个问题。 (问题:我必须编辑协议第3行[MARATHON]) 这是文件: # /etc/ndxconfig.ini will override this file # if APP_ID is added in service propery, service discovery will be using marathon; # HOST/PORT specified will override values retrieved from marathon [MARATH

嗨,最近我发布了一个问题。
(问题:我必须编辑
协议
第3行
[MARATHON]

这是文件:

# /etc/ndxconfig.ini will override this file
# if APP_ID is added in service propery, service discovery will be using marathon;
# HOST/PORT specified will override values retrieved from marathon

[MARATHON]
HOSTS = {{ ','.join(groups['marathon'])}}
PORT = 8080
PROTOCOL = http
SECRET = SGpQIcjK2P7RYnrdimhhhGg7i8MdmUqwvA2JlzbyujFS4mR8M88svI7RfNWt5rnKy4WHnAihEZmmIUb940bnlYmnu47HdUHE


[MYSQL]
; APP_ID = /neon/infra/mysql
HOST = {{keepalived_mysql_virtual_ip}}
PORT = 3306
SECRET = tIUFN1rjjDBdEXUsOJjPEtdieg8KhwTzierD48JsgDeYc84DD6Uy5a6kzHfKolq1MNS1DKwlSqxENk33UulJd9DPHPzYCxFm
问题是,如果我在某些情况下重新运行脚本,
sed'/\[MARATHON\]/{N;N;N;s/http/https/;}
将越来越多的
s
附加到
http
httpssss
)。
因此,我将在正则表达式中为
s
添加一个正向前瞻。 我可以用perl-pe来做,但不知道如何在匹配项下的第n行上做。
请帮忙。如何操作?

如果您使用的是GNU-sed,解决方案可以使用单词边界:

sed '/\[MARATHON\]/{N;N;N;s/\<http\>/https/;}' file 
#                          ^^     ^^

\(.*.*).
将匹配并捕获带有
=
和可选空格的密钥,其值将使用
\1
还原,而
https
将始终重新写入值。

尝试使用这一行程序,它完全符合您的要求:在Perl中的某个特定匹配项下编辑n行字符串。但也要考虑<强>注释<强>下面。

cat file | perl -lpe '
$seen = 1 if m{\[MARATHON\]}xms;
$num_lines++ if $seen;
s{ \A ( PROTOCOL \s+ = \s+ ) http }{${1}https}xms if $num_lines == 4;
'
注意事项:

上面的代码回答了这个问题,但它是糟糕的代码。为什么?通常,只依赖预期的模式和预期的行数来解析已知的、广泛使用的格式是一个坏主意。这里,格式似乎是“代码> .ini”/代码>,因此考虑搜索用于解析/读/写的模块/库<代码> CONFIGIN/<代码>文件。例如:

  • Config::ini文件-用于读取.ini样式配置文件的模块:

  • Config::INI-simple.INI文件格式:

如果您不想使用上面的模块,那么至少考虑对输入的可能的未来变化,并在代码中使用更少的假设。在这种情况下,从节头开始的第n行的假设似乎是最不可靠的。写入此文件的上游代码中的

ini
解析器可能不关心行的顺序。节标题更健壮。也许可以读取整个文件(
slurp
),并使用非贪婪的多行正则表达式从
[MARATHON]
更改为
https
,从
[MARATHON]
PROTOCOL=http
。不要指定确切的行数,只需确保更改的行位于同一节中即可但这仍在重塑方向盘-如果可以,请避免这样做。

另请参见:


很高兴参考另一个问答,但在本文中添加与当前问题相关的所有详细信息。。例如:不清楚为什么需要多次运行脚本。。在任何情况下,您给定的示例都可能使用
s/http$/https/
,因此
http
仅当它位于行的末尾时才会更改。您可以在GNU
sed
中使用单词边界:
sed'/\[MARATHON\]/{N;N;N;s/\/https/;}
为第一个问题添加了非perl的答案。
cat file | perl -lpe '
$seen = 1 if m{\[MARATHON\]}xms;
$num_lines++ if $seen;
s{ \A ( PROTOCOL \s+ = \s+ ) http }{${1}https}xms if $num_lines == 4;
'