繁体   English   中英

使用awk或sed合并/打印与模式匹配的行(单一行吗?)

[英]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

greppaste和流程替换

$ 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' infilegrep '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|$) :换行符或模式空间的末尾–这是为了使交换也位于最后一行,而我们没有模式空间末尾的换行符。
  • 这适用于GNU sed。 对于MacOS中的BSD sed,需要进行一些更改:
    • -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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM