在bash中多行匹配后附加一个字符串

时间:2017-09-12 13:57:59

标签: bash awk sed

我需要一个sedawk命令在bash中多行匹配后打印一行。例如,将此文件作为输入:

admin:
  users:
    - user1
    - user2

read_only:
  users:
    - user3

write_only:
  users:
    - user4

access_only:
  users:
    - user5
    - user6

..我需要将此作为输出:

admin:
  users:
    NEW USER
    - user1
    - user2

read_only:
  users:
    - user3

write_only:
  users:
    - user4

access_only:
  users:
    - user5
    - user6

正则表达式应匹配前两行admin: users:,然后附加NEW USER行。

怎么做?我应该使用sed还是awk?怎么样? 谢谢

7 个答案:

答案 0 :(得分:2)

都不是。它是YAML,因此将其解析为YAML。

#!/usr/bin/env perl

use strict;
use warnings;

use YAML;
use Data::Dumper;

my $stuff = Load ( do { local $/; <DATA> } );

print Dumper $stuff; 

print $stuff->{admin}{users}[0],"\n";

print "List:\n";
print join "\n", @{$stuff->{admin}{users}};

__DATA__
admin:
  users:
    - user1
    - user2

鉴于您已将问题更新为“向管理员用户节添加新用户”,我的答案已更改 - 但仍然是'使用perl':

#!/usr/bin/env perl

use strict;
use warnings;

use YAML::Syck;
use Data::Dumper;

$YAML::Syck::SortKeys = 1;

my $stuff = Load ( do { local $/; <DATA> } );

print Dumper $stuff; 

push @{$stuff->{admin}{users}}, "new username";

print Dumper $stuff;

print Dump \$stuff;


__DATA__
admin:
  users:
    - user1
    - user2

read_only:
  users:
    - user3

write_only:
  users:
    - user4

access_only:
  users:
    - user5
    - user6

你可以单行 - 如果这样:

perl -0777 -MYAML -e '$s = Load(<>);unshift @{$s->{admin}{users}}, "new username"; print Dump $s;'

这将从STDIN读取,执行转换并输出有效的YAML。 unshift会在数组的开头插入用户名 - 我通常会使用push将其插入到最后。

注意 - 我在前一个示例中使用了YAML::Syck,因为它会对输出进行排序。

答案 1 :(得分:2)

sed用于单独行的简单替换,全部。对于其他任何事情,您应该使用awk来实现简单性,清晰度,效率,稳健性以及软件的大多数其他理想属性。

使用GNU awk进行多字符RS和gensub():

$ awk -v RS='^$' '{$0=gensub(/(admin:\s+users:)(\s+)/,"\\1\\2NEW LINE\\2",1)}1' file
admin:
  users:
    NEW LINE
    - user1
    - user2

答案 2 :(得分:0)

请您试着跟随并告诉我这是否对您有帮助。

awk '/^$/{check=""}/admin/{check=1;print;next} /users:/{check++;print;next} check==2{print "    NEW LINE or OP text here.";check="";} 1' Input_file

答案 3 :(得分:0)

如果您在Unix(或其他未使用回车字符的环境)中工作,您可以通过临时替换新行来使用sed:

cat file | tr '\n' '\r' | sed "s/admin:\r  users:/admin:\r  users:\r    NEW LINE/g" | tr '\r' '\n'

不可否认比上面的awk解决方案更令人讨厌,但是为那些想知道如何使用sed轻松实现它的人添加了这个。

答案 4 :(得分:0)

awk 解决方案:

awk '/^admin/{ n=NR+2 }NR==n{ sp=substr($0,1,index($0,"-")-1); 
     printf "%s\n%s\n",sp"NEW USER",$0; next  }1' file

输出:

admin:
  users:
    NEW USER
    - user1
    - user2

read_only:
  users:
    - user3

write_only:
  users:
    - user4

access_only:
  users:
    - user5
    - user6

答案 5 :(得分:0)

使用sed

/^[a-z_]\+://^$/之间划分阻止,因此您可以在一个区块内执行somme过程:

sed -e $'/^admin:/,/^$/{/users:/a\    NewUser\n}'

这可以写成:

NEWUSER="user2017"
sed -e "/^admin:/,/^$/{
    /users:/a\    - $NEWUSER
}"

(通过使用双引号,我可以使用命令行或脚本中的变量)

这将呈现:

admin:
  users:
    - user2017
    - user1
    - user2

read_only:
  users:
    - user3

...

...

myadduser () { 
    local crt= line;
    while IFS= read line; do
        echo "$line";
        [ "$line" ] && { 
            [ "${line:0:1}" != " " ] && crt=${line%:} || { 
                [ "${line//*([: ])}" = "users" ] &&
                    [ "$crt" = "${2:-admin}" ] &&
                        printf "    - %s\n" $1
            }
        };
    done
}

可以使用:

myadduser NewAdminUser <file.txt
admin:
  users:
    - NewAdminUser
    - user1
    - user2

read_only:
  users:
    - user3

...

或使用可选的第二个参数:

myadduser NewWriteUser write_only
admin:
  users:
    - user1
    - user2

read_only:
  users:
    - user3

write_only:
  users:
    - NewWriteUser
    - user4

access_only:
  users:
    - user5
    - user6

但请,

阅读Sobrique's fine answer

使用进行原型设计,例如使用进行最终编程,您可以找到合适的库。

也可以使用中的任何一个库。

第一个管理员用户
perl -MYAML -E 'undef$/;$s = Load(<>);say@{$s->{admin}->{users}}[0];'
管理员用户数
perl -MYAML -E 'undef$/;$s = Load(<>);say scalar@{$s->{admin}->{users}};' 

答案 6 :(得分:0)

这可能适合你(GNU sed):

sed -i '/admin:/!b;n;/users:/!b;n;h;s/-.*/- new user/p;g' file

如果该行不包含admin:拯救。同样,如果以下行不包含users:拯救。阅读并复制以下行,修改该行以包含- new user,然后将其打印出来并原始。

相关问题