使用awk解析多行

时间:2017-02-20 17:02:26

标签: linux bash shell awk

我有一个多行输出,如下所示:

foo: some text
    goes here
    and here
    and here
bar: more text
    goes here
    and here
xyz: and more...
    and more...
    and more...

文本的格式如下所示。我感兴趣的文本的“组/部分”在行开始之后立即开始,并在下一个文本在行的开头处开始之前的行结束。

在这个例子中,小组将是foo,所有文本都在bar之前。然后barxyz之前的所有文字。最后,xyz直到最后。

3 个答案:

答案 0 :(得分:2)

<强>输入

$ cat file
foo: some text
    goes here
    and here
    and here
bar: more text
    goes here
    and here
xyz: and more...
    and more...
    and more...

<强>输出

$ awk '/:/{f=/^foo/}f' file
foo: some text
    goes here
    and here
    and here

如果您想跳过匹配的行

,请注意
$ awk '/:/{f=/^foo/;next}f' file
    goes here
    and here
    and here

甚至

# Just modify variable search value
# 1st approach
$ awk -v search="foo" '/:/{f=$0~"^"search}f' file
foo: some text
    goes here
    and here
    and here

# 2nd approach
$ awk -v search="foo" '/:/{f=$0~"^"search;next}f' file
    goes here
    and here
    and here

答案 1 :(得分:0)

如果我正确地解释了您的问题,您只想删除空白并将foo放在与:之后的部分不同的行上。这个awk脚本会这样做:

awk 'BEGIN{RS="[:\n]"}{$1=$1}1' file

输出:

foo
some text
goes here
and here
and here
bar
more text
goes here
and here
xyz
and more...
and more...
and more...

说明:

  • RS="[:\n]表示应在:\n
  • 拆分行
  • $1=$1将该行重新处理为$0(删除行尾的空格)
  • 1表示每一行都应该是“默认操作”的进程,即print $0

答案 2 :(得分:0)

正如其他人所说的那样,一旦你解析了数据,就没有指定你想要对数据做什么。

如果您只是想提取一个特定的块,Akshay Hegde的答案应该可以正常工作。

如果你想使用更多awk功能来处理每个记录,例如以某种方式转换输出(例如将行连接在一起等),你可能需要一些不同的东西。

有几种相当简单的方法可以做到这一点,但我认为最好的方法可能是更改记录分隔符。

使用正则表达式作为记录分隔符的能力是一个gawk扩展,但如果你在Linux上,你可能正在使用gawk。

以下是gawk程序文件“prog.awk”的内容:

function process_group(name, body) {
    print "Got group with name '" name "'";
    print body;
}

BEGIN {
    RS="(\n|^)\\S+:"
    PREV=""
}

{
    if (PREV!="") {
        process_group(gensub(/\n?(\S+):/, "\\1", "", PREV), $0);
    }
    PREV=RT
}

您可以使用

运行此功能
gawk -f prog.awk input.txt

或者你可以把整个东西放在gawk命令行上,但是如果它的格式很好就会更容易阅读。

这个想法是,每次看到记录分隔符时,它都会为您提供自上一个记录分隔符或文件开头以来的内容。这意味着它第一次看到记录分隔符时它用记录分隔符“foo:”和一个空体来调用底部块,第二次它看到记录分隔符时它用“bar:”调用块并且之间的内容“foo:”和“bar:”等等。

这意味着每个块对应的记录分隔符是前一个,而不是当前块。通过跟踪“PREV”变量中的前一个记录分隔符,可以很容易地处理这个问题。

因此,BEGIN块设置记录分隔符RS,并将PREV初始化为空。

底部的块为RS分隔的每条记录调用,再次在文件末尾调用。

如果“PREV”不为空,则使用当前正文数据和前一个记录分隔符调用“process_group”函数(在使用gensub的过程中从PREV中删除不感兴趣的位)。然后它将当前匹配记录分隔符(RT)分配给PREV以供下次使用。

在“process_group”中,您可以对每个组执行任何处理。在这种情况下,我只是将它们打印出来,但应该很容易修改它以做任何你想做的事情。