在匹配字符串的下一行插入一个缩进的文本

Insert a text with indentation persevered on the next line of matched string

我有一个包含如下 yaml 数据的文件:

cat x.yml
foo:
 - bar: 1
 - zoo: 2

我可以插入文本,但这弄乱了缩进(见第二行):

sed -r '/^[ ]+- bar:/a- hoo: 3' x.yml
foo:
 - bar: 1
- hoo: 3
 - zoo: 2

然后,我尝试反向引用前导空格,但似乎它不适用于 /a 标志。

sed -r '/^([ ]+)- bar:/a- hoo: 3' x.yml
foo:
 - bar: 1
1- hoo: 3
 - zoo: 2

使用单行对获得以下有什么帮助吗?

foo:
 - bar: 1
 - hoo: 3
 - zoo: 2

我建议切换到 GNU sed 的 s 命令:

sed -E 's/( *)- bar:.*/&\n- hoo: 3/' file

输出:

foo:
 - bar: 1
 - hoo: 3
 - zoo: 2

参见:man sedThe Stack Overflow Regular Expressions FAQ

首先,我同意 Inian 的说法,YML 解析器在这里更合适。

不过,您可以使用 s 命令并捕获组,而不是

$ sed -r 's/^([ ]+)- bar:(.+)$/- bar:\n- hoo: 3/' x.yml

这给出了

foo:
 - bar: 1
 - hoo: 3
 - zoo: 2

最好的选择可能是使用解析器。如果您确切知道值应该在哪里,您可以将它们弹出到那里。否则,您将不得不循环查找“bar”键。这是使用 YAML 模块。

use strict;
use warnings;
use YAML;

my $yaml = do { local $/; <> };
my $href = Load($yaml);
for (0 .. $#{ $href->{foo} }) {
    if (grep { $_ eq "bar" } keys %{ $href->{foo}[$_] }) {
        splice @{ $href->{foo} }, $_+1, 0, { hoo => 1 };
    }
}
print Dump $href;

它输出:

foo:
  - bar: 1
  - hoo: 1
  - zoo: 2

否则你可以像这样使用 Perl:

$ perl -pe's/^( *- *)bar.*\K/hoo: 1\n/s' x.yml
foo:
 - bar: 1
 - hoo: 1
 - zoo: 2

从行首捕获 ^ 一个被破折号包围的破折号。期望“bar”,然后将其之后的所有内容吸收到正则表达式匹配中,包括末尾的换行符(因此 /s 修饰符)。保留 (\K) 匹配的所有内容,然后添加捕获的 dash-string,加上您的新内容和换行符。完成。