Grep - 正则表达式,用于匹配多个键值对并返回单行

时间:2014-01-10 13:32:01

标签: regex grep pcre

我有以下输入:

TAG1 VALUE1;TAG2 VALUE2;sometext;TAG3 VALUE3;sometext;TAG4 VALUE4;TAG5 VALUE5;sometext
TAG1 VALUE1;sometext;TAG3 VALUE3;sometext;TAG4 VALUE4;TAG5 VALUE5;sometext
TAG1 VALUE1;TAG2 VALUE2;sometext;TAG3 VALUE3;sometext;TAG4 VALUE4;TAG5 VALUE5
TAG1 VALUE1;TAG2 VALUE2;sometext;TAG3 VALUE3;sometext;TAG5 VALUE5;sometext
TAG1 VALUE1;TAG2 VALUE2;sometext;

我需要以下输出:

TAG2 VALUE2;TAG3 VALUE3;TAG5 VALUE5;
TAG3 VALUE3;TAG5 VALUE5;
TAG2 VALUE2;TAG3 VALUE3;TAG5 VALUE5;
TAG2 VALUE2;TAG3 VALUE3;TAG5 VALUE5;
TAG2 VALUE2;

或者,或者与上面相同,但只有值

我试过以下:

grep -oP '(?<=TAG2 ).*?(?=;)|(?<=TAG3 ).*?(?=;)|(?<=TAG5 ).*?(?=;)'

它有效,但每个值都在不同的行中:

VALUE2
VALUE3
VALUE5

我不能假设所有行都有所有标记,所以每一行输入我真的需要一行输出。首选本机Linux工具 - sed,awk,grep等。

谢谢!

3 个答案:

答案 0 :(得分:2)

使用awk

$ awk 'BEGIN{FS=OFS=";"}{print $2, $4, $7}' file
TAG2 VALUE2;TAG3 VALUE3;TAG5 VALUE5
  • BEGIN{FS=OFS=";"}将输入和输出字段分隔符设置为;
  • {print $2, $4, $7}根据该分隔符打印第2,第4和第7个字段。

  

我希望解析键/值对的原因不是   必须存在所有键,而不一定是相同的   列(但至少它们按特定顺序存在,TAG1是   首先,TAG2下一个等...)

然后这样的事情应该成功:

awk -v values="TAG1 TAG5"
       'BEGIN{split(values, vals, " ")}
        {a[$1]=$2}
        END{for (i in vals) print vals[i], a[vals[i]]}'
     RS=";" file
  • -v values="TAG1 TAG5"密码以解析要分析的值。
  • 'BEGIN{split(values, vals, " ")}将它们存储到vals[]数组中。
  • {a[$1]=$2}保存a["TAG1"] = "VAL1"匹配。
  • END{for (i in vals) print vals[i], a[vals[i]]}'打印匹配。
  • RS=";"将记录分隔符设置为;,以便我们可以处理文件中的几个值。

示例:

$ awk -v values="TAG1 TAG3" 'BEGIN{split(values, vals, " ")} {a[$1]=$2} END{for (i in vals) print vals[i], a[vals[i]]}' RS=";" file
TAG1 VALUE1
TAG3 VALUE3
$ awk -v values="TAG1 TAG6" 'BEGIN{split(values, vals, " ")} {a[$1]=$2} END{for (i in vals) print vals[i], a[vals[i]]}' RS=";" file
TAG1 VALUE1
TAG6 

答案 1 :(得分:1)

这是一种perl方式:

$ perl -ne 'print $1," " while(/(?<=TAG[235] )(.*?)(?=;)/g); print "\n";'  in.txt

根据评论编辑:

$ perl -ne 'print $1," " while(/(?<=(?:DEV|SRC|DST|ACT) )(.*?)(?=;)/g); print "\n";'  in.txt

在行动中:

$ cat in.txt
TAG1 VALUE1;TAG2 VALUE2;sometext;TAG3 VALUE3;sometext;TAG4 VALUE4;TAG5 VALUE5;sometext
TAG1 VALUE1;sometext;TAG3 VALUE3;sometext;TAG4 VALUE4;TAG5 VALUE5;sometext
TAG1 VALUE1;TAG2 VALUE2;sometext;TAG3 VALUE3;sometext;TAG4 VALUE4;TAG5 VALUE5
TAG1 VALUE1;TAG2 VALUE2;sometext;TAG3 VALUE3;sometext;TAG5 VALUE5;sometext
TAG1 VALUE1;TAG2 VALUE2;sometext;

$ perl -ne 'print $1," " while(/(?<=TAG[235] )(.*?)(?=;)/g); print "\n";'  in.txt
VALUE2 VALUE3 VALUE5 
VALUE3 VALUE5 
VALUE2 VALUE3 
VALUE2 VALUE3 VALUE5 
VALUE2 

答案 2 :(得分:0)

使用纯BASH:

l='TAG1 VALUE1;TAG2 VALUE2;sometext;TAG3 VALUE3;sometext;TAG4 VALUE4;TAG5 VALUE5;sometext'
( IFS=';' && read -a arr <<< "$l"; echo "${arr[1]}; ${arr[3]}; ${arr[6]};" )
TAG2 VALUE2; TAG3 VALUE3; TAG5 VALUE5;
  • IFS=';'在将行读入数组时将分隔符设为;