我想在几个文件中出现的特定模式中插入一行,我首先尝试用sed做,然后我意识到这个任务的完美工具将是perl。
所以,我试过了(灵感来自这里Multiline search replace with Perl):
perl -i.bak -pe 'BEGIN{undef $/;} s/(.*)markers:(.*)text:(.*)\n/$1markers:$2text:$3\nlink:/smg' myfile
在此档案中:
module_map:
markers:
- x: 1
'y': 1
text: "hello world"
popup: true
- x: 2
'y': 2
text: 'hello world'
popup: false
得到那个:
module_map:
markers:
- x: 1
'y': 1
text: "hello world"
link:
popup: true
- x: 2
'y': 2
text: 'hello world'
link:
popup: false
(注意“text:”行后面的“link:”行)
我找不到任何有效的解决方案。你有什么想法吗?
感谢您阅读:)
答案 0 :(得分:3)
您似乎正在尝试编辑YAML文件。为什么不使用专用模块?
#!/usr/bin/perl
use warnings;
use strict;
use YAML;
my $s = << '---';
module_map:
markers:
- x: 1
'y': 1
text: "hello world"
popup: true
- x: 2
'y': 2
text: 'hello world'
popup: false
---
my $href = Load($s);
for my $inner (@{ $href->{module_map}{markers} }) {
$inner->{link} = undef if exists $inner->{text};
}
print Dump($href);
请注意,我必须修复输入数据的缩进。在输出中,您将看到
link: ~
我不确定您是否可以link:
没有价值(YAML和YAML::Tiny的空值往返~
。)
答案 1 :(得分:2)
我不会尝试在regex
中完成所有操作。
如果您这样做,这很容易:
while ( <> ) {
print " link:\n" if m/popup/;
print;
}
你可以单行:
perl -pe 'print " link:\n" if m/popup/;'
如果您查看perlrun
或通过-MO=Deparse
执行此操作,-p
标记的功能就是包含您的可执行文件&#39;东西:
LINE: while (defined($_ = <ARGV>)) {
print " link:\n" if /popup/;
}
continue {
die "-p destination: $!\n" unless print $_;
}
这意味着你可以做一个简单的s///
模式转换。您甚至可以在使用-i
进行就地编辑的同时执行此操作。
注意(如评论中所述)可以在perlre
中找到有关m//
和s///
的更多信息 - m/
表示模式匹配。如果您没有另行说明,则默认为$_
的当前内容。
s///
是一种sed风格的模式替换。例如。 s/replacethis/withthis/
。它默认也适用于$_
。
如果你的逻辑比这复杂一点(这样可以很好地处理你的样本数据),那么根据记录分隔符来考虑可能是有用的 - 你可以将$/
设置为记录分隔符,所以你可以在一个&#34; go&#34;中处理一个块。您可以在perlvar
中查看更多相关信息 - 默认情况下,它是&#34;换行&#34;所以你一次迭代一行文件,但你可以将它设置为任何字符串值。 (但请注意 - 不是正则表达式)。或者将其设置为undefined,然后它将一次性读取整个文件。
E.g。在您的上方,您可以将其设置为&#39; - &#39;因此你最终得到:
local $/ = '-';
while ( <> ) {
if ( m/text/ and m/popup/ ) {
s/^(\s*popup)/ link:\n$1/m;
}
print;
}
正则表达式末尾的 /m
(也在perlre
中描述)表示跨越多行&#39;。这是必需的,因为我们正在使用多行块。