我需要一个sed
或awk
命令在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?怎么样? 谢谢
答案 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
使用perl或python进行原型设计,例如使用c进行最终编程,您可以找到合适的库。
也可以使用shell中的任何一个库。
第一个管理员用户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
,然后将其打印出来并原始。