您好,我最近发布了一个问题。
edit nth line below a line match in bash?
(问题:我必须在PROTOCOL
下面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/;}' <file>
将越来越多的s
附加到http
(httpsssss
)。
因此,我将在s
的正则表达式中添加积极的前瞻性。
我可以使用 perl -pe 来做到这一点,但不知道如何在比赛下方的第n行进行。
请帮忙。我该怎么办?
答案 0 :(得分:2)
如果您使用的是GNU sed,则解决方案可以使用单词边界:
sed '/\[MARATHON\]/{N;N;N;s/\<http\>/https/;}' file
# ^^ ^^
您还可以利用上下文详细信息。由于http
在PROTOCOL
之后,您可以简单地使用它来重置值:
sed '/\[MARATHON\]/{N;N;N;s/\(.*= *\).*/\1https/;}' file
\(.*= *\).*
将与=
和可选空格进行匹配和捕获,并且其值将由\1
恢复,而https
将始终重写该值。 / p>
答案 1 :(得分:2)
尝试使用这种单行代码,它可以完全满足您的要求:在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
,因此请考虑搜索用于解析/读取/写入config ini
文件的模块/库。例如:
Config :: IniFiles-读取.ini样式的配置文件的模块:https://metacpan.org/pod/Config::IniFiles
Config :: INI-简单的.ini文件格式:https://metacpan.org/pod/Config::INI
如果您不想使用上述模块,请至少考虑将来可能对输入进行的更改,并在代码中使用较少的假设。在这种情况下,从节标题开始的第 n 行的假设似乎具有最低更改的鲁棒性。写入此文件的上游代码中的ini
解析器可能并不关心行的顺序。节标题更健壮。也许读取了整个文件(slurp
,然后使用非贪婪的多行正则表达式从https
到[MARATHON]
更改为PROTOCOL = http
。不要指定确切的行数,只需确保更改的行在同一部分即可。 但这仍然是在重新发明轮子-如果可以的话,请避免这样做。
另请参见: