[英]Using awk or sed to merge / print lines matching a pattern (oneliner?)
我有一个包含以下文本的文件:
subject:asdfghj
subject:qwertym
subject:bigger1
subject:sage911
subject:mothers
object:cfvvmkme
object:rjo4j2f2
object:e4r234dd
object:uft5ed8f
object:rf33dfd1
我希望使用awk或sed达到以下结果(因为oneliner会是一个奖励![Perl oneliner也可以接受]):
subject:asdfghj,object:cfvvmkme
subject:qwertym,object:rjo4j2f2
subject:bigger1,object:e4r234dd
subject:sage911,object:uft5ed8f
subject:mothers,object:rf33dfd1
我想将匹配“主题”和“对象”的每一行按列出的顺序组合在一起,并用逗号分隔。 我可以看看用awk,sed或perl完成的示例吗? (如果可能的话,最好是单线吗?)
我已经尝试了awk的一些用法来执行此操作,但我仍在学习应该添加:
awk '{if ($0 ~ /subject/) pat1=$1; if ($0 ~ /object/) pat2=$2} {print $0,pat2}'
但是没有按照我的意愿去做! 所以我知道我的语法错误。 如果我看到一个对我有很大帮助的示例,那么我可以学习。
不是perl或awk,而是更容易。
$ pr -2ts, file
subject:asdfghj,object:cfvvmkme
subject:qwertym,object:rjo4j2f2
subject:bigger1,object:e4r234dd
subject:sage911,object:uft5ed8f
subject:mothers,object:rf33dfd1
说明
-2
2列
t
忽略打印标题(文件名,日期,页码等)
s,
使用逗号作为列分隔符
我会在perl
这样做:
#!/usr/bin/perl
use strict;
use warnings;
my @subjects;
while ( <DATA> ) {
m/^subject:(\w+)/ and push @subjects, $1;
m/^object:(\w+)/ and print "subject:",shift @subjects,",object:", $1,"\n";
}
__DATA__
subject:asdfghj
subject:qwertym
subject:bigger1
subject:sage911
subject:mothers
object:cfvvmkme
object:rjo4j2f2
object:e4r234dd
object:uft5ed8f
object:rf33dfd1
减少到一个班轮,这将是:
perl -ne '/^(subject:\w+)/ and push @s, $1; /^object/ and print shift @s,$_' file
grep
, paste
和流程替换
$ paste -d , <(grep 'subject' infile) <(grep 'object' infile)
subject:asdfghj,object:cfvvmkme
subject:qwertym,object:rjo4j2f2
subject:bigger1,object:e4r234dd
subject:sage911,object:uft5ed8f
subject:mothers,object:rf33dfd1
由于进程替换( <( )
),这会将grep 'subject' infile
和grep 'object' infile
的输出视为文件,然后将结果与paste
一起paste
,使用逗号作为分隔符(由-d ,
表示)。
sed
想法是读取所有主题行并将其存储在容纳空间中,然后针对每条对象线获取容纳空间,获取适当的主题并将其余主题线放回容纳空间中。
首先是无法阅读的单线:
$ sed -rn '/^subject/H;/^object/{G;s/\n+/,/;s/^(.*),([^\n]*)(\n|$)/\2,\1\n/;P;s/^[^\n]*\n//;h}' infile
subject:asdfghj,object:cfvvmkme
subject:qwertym,object:rjo4j2f2
subject:bigger1,object:e4r234dd
subject:sage911,object:uft5ed8f
subject:mothers,object:rf33dfd1
-r
用于扩展的正则表达式(不转义括号, +
和|
),并且-n
默认情况下不打印。
扩展,更易读和解释:
/^subject/H # Append subject lines to hold space
/^object/ { # For each object line
G # Append hold space to pattern space
s/\n+/,/ # Replace first group of newlines with a comma
# Swap object (before comma) and subject (after comma)
s/^(.*),([^\n]*)(\n|$)/\2,\1\n/
P # Print up to first newline
s/^[^\n]*\n// # Remove first line (can't use D because there is another command)
h # Copy pattern space to hold space
}
备注:
H
一个),因此,用逗号分隔的换行符替换了一个或多个换行符,因此\\n+
:第一次是两个换行符,一个用于其余的部分。 (\\n|$)
:换行符或模式空间的末尾–这是为了使交换也位于最后一行,而我们没有模式空间末尾的换行符。 -r
选项必须由-E
代替。 h;}
\\n
替换为'$'\\n''
或'"$(printf '\\n')"'
。 由于您专门要求“单一”,我认为简洁对您而言比清晰重要得多,因此:
$ awk -F: -v OFS=, 'NR>1&&$1!=p{f=1}{p=$1}f{print a[++c],$0;next}{a[NR]=$0}' file
subject:asdfghj,object:cfvvmkme
subject:qwertym,object:rjo4j2f2
subject:bigger1,object:e4r234dd
subject:sage911,object:uft5ed8f
subject:mothers,object:rf33dfd1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.