2012-10-30 82 views
5

我想用awk解析多行表达式。它们中的一种,是这样的:awk和多行匹配(sub-regex)

_begin hello world ! 
_attrib0 123 
_attrib1 super duper 
_attrib1 yet another value 
_attrib2 foo 
_end 

我需要提取关联_begin和_attrib1值。因此,在该示例中,awk脚本应返回(每行一个):

hello world ! super duper yet another value 

使用的隔板是一标签(\ t)的字符。空格仅在字符串中使用。

回答

8

以下awk脚本做这项工作:你是否希望有一个标签(\t)是你输出域分隔

#!/usr/bin/awk -f 
BEGIN { FS="\t"; } 
/^_begin/  { output=$2; } 
$1=="_attrib1" { output=output " " $2; } 
/^_end/  { print output; } 

没有指定。如果你这样做,让我知道,我会更新答案。 (或者你可以,它是微不足道的。)

当然,如果你想有一个可怕的替代方案(因为我们正在接近万圣节),这里的解决方案使用sed

$ sed -ne '/^_begin./{s///;h;};/^_attrib1[^0-9]/{s///;H;x;s/\n/ /;x;};/^_end/{;g;p;}' input.txt 
hello world ! super duper yet another value 

如何这项工作? Mwaahahaa,我很高兴你问。

  • /^_begin./{s///;h;}; - 当我们看到_begin,剥离其关闭,该行的其余部分存储的sed的“保持缓冲器”。
  • /^_attrib1[^0-9]/{s///;H;x;s/\n/ /;x;}; - 当我们看到_attrib1,剥离其关闭,将其追加到保持缓冲器交换保持缓冲器和模式空间,用空格代替换行,并再次交换保持缓冲器和模式空间。
  • /^_end/{;g;p;} - 我们已经达到了最后,将保持缓冲区拖入模式空间并打印出来。

这假定您的输入字段分隔符只是一个选项卡。

很简单。谁曾说过sed是神秘的?!

+0

_attrib11正在此脚本失败(_attrib1匹配) – malat

+0

有您所提供的样本数据中没有'_attrib11'。如果你喜欢,你可以像'$ 1 ==“_ attrib1”'而不是'/^_ attrib1 /'来处理它,或者你可以把它作为一个正则表达式来终止它,就像'$ 1〜/^_ attrib1 $ /'。我建议第一个备用解决方案;总是先选择字符串匹配,正则表达式(至少)秒。 – ghoti

+0

根据您的新要求更新我的答案。还增加了一个'sed'替代方案,为您的阅读乐趣。 – ghoti

1

这应该工作:

#!/bin/bash 

awk 'BEGIN {FS="\t"} {if ($1=="_begin" || $1=="_attrib1") { output=output " " $2 }} END{print output}'