使用awk使每个字段遵循常规模式

时间:2015-04-22 08:06:36

标签: awk pattern-matching

输入文本文件如下:

1234, aaa = 34 </T><AT/>X_CONST = 34 </T><AT/>AAA_Z = 3 </T><AT/>Y_CONST = 34 </T><AT/>FOUND_ME_1 = 5 </T><AT/>BBB_X = 3 </T><AT/>CCC_X = 8 </T><AT/>FOUND_ME_2 = 8 </T><AT/>FOUND_ME_3 = 8 </T><AT/>RRR_Z = 3 </T><AT/>T_CONST = 37 </T><AT/>FOUND_ME_4 = 10 </T><AT/>X_CONST = 34
7844, aaa = 33 </T><AT/>X_CONST = 21 </T><AT/>AAA_Z = 3 </T><AT/>R_CONST = 34 </T><AT/>FOUND_ME_1 = 50 </T><AT/>BBB_X = 3 </T><AT/>CCC_X = 8 </T><AT/>FOUND_ME_2 = 81 </T><AT/>FOUND_ME_3 = 8 </T><AT/>RRR_Z = 3 </T><AT/>T_CONST = 37 </T><AT/>X_CONST = 55
8888, aaa = 31 </T><AT/>X_CONST = 21 </T><AT/>AAA_Z = 3 </T><AT/>R_CONST = 34 </T><AT/>FOUND_ME_1 = 54 </T><AT/>BBB_Z = 3 </T><AT/>CCC_X = 8 </T><AT/>FOUND_ME_2 = 81 </T><AT/>FOUND_ME_3 = 8 </T><AT/>RRR_Z = 3 </T><AT/>T_CONST = 37 </T><AT/>FOUND_ME_4 = 11 </T><AT/>X_CONST = 55 </T><AT/>FOUND_ME_5 = 8 </T><AT/>TTT_X = 8 </T><AT/>FOUND_ME_6 = 20

我需要提取与字段FOUND_ME_ [0-9]相关的所有值,可能还有awk。我知道将每个字段转换为单独的行会更容易,但我找到了一个使用该文件的解决方案。

我的目标是输出如下所示(以逗号分隔的值)

5, 8, 8, 10
50, 81, 8
54, 81, 8, 11, 8, 20

我正在尝试以下但没有运气:

awk '{for(i=1;i<=NF;i++){ if($i==".*FOUND_ME_[0-9]"){print $($i+2)} } }'

我对这个特殊的常规模式FOUND_ME_ [0-9]

也有问题

2 个答案:

答案 0 :(得分:1)

这个awk脚本可以获得你想要的输出(虽然我猜这个文件可能一次只能用XML开始......):

$ cat script.awk
BEGIN { FS = "[[:space:]=]+" }
{
    s = ""
    for (i = 1; i <= NF; ++i) 
        if($i ~ /FOUND_ME_[0-9]/)
            s = s sprintf("%s, ", $(++i)) 
    print substr(s, 1, length(s) - 2)
}
$ awk -f script.awk file
5, 8, 8, 10
50, 81, 8
54, 81, 8, 11, 8, 20

在每个匹配模式后,从字段构建字符串ssprintf("%s, ", $(++i))返回下一个字段的值,后跟逗号和空格。 $(++i)递增字段编号i,然后返回字段的值。在awk中,字符串是连接的,因此sprintf返回的字符串会添加到现有值s

我将字段分隔符FS设置为一个或多个空格或=字符,因此您感兴趣的字段是与模式匹配的字段之后的字段。请注意,我使用~来匹配正则表达式模式 - 您不能像执行字符串比较那样使用==

substr在打印之前从字符串中删除最后一个,

一个更短的选项,灵感来自GNU awk上的Kent's use of FPAT(请注意,这需要版本&gt; = 4.0):

$ awk -v FPAT="FOUND_ME_[0-9] *= *[0-9]+" -v OFS=", " '{$1=$1;gsub(/FOUND_ME_[0-9] *= */,"")}1' file
5, 8, 8, 10
50, 81, 8
54, 81, 8, 11, 8, 20

$1=$1会导致awk“触摸”每条记录,删除与FPAT不匹配的部分。 gsub执行全局替换,删除我们不感兴趣的部分。最后1始终为true,因此执行默认操作{print}。设置OFS变量会导致输出中的每个字段按照需要以逗号分隔。

答案 1 :(得分:0)

gawk FPAT,我们可以用它来解决这个问题:

awk -v FPAT="FOUND_ME_[0-9] *= *[0-9]+" '
  {for(i=1;i<=NF;i++){sub("FOUND_ME_[0-9] *= *","",$i);
    printf "%s%s",$i,(NF==i?"\n":", ")}}' file

输出:

5, 8, 8, 10
50, 81, 8
54, 81, 8, 11, 8, 20