将行转换为半结构化数据的列

时间:2016-09-20 02:21:20

标签: unix text awk sed grep

我有一个看起来像这样的数据集

<SUBBEGIN
    IMSI=xxxxxxxxxxxx;
    MSISDN=xxxxxxxxx;
    DEFCALL=TS11;
    CURRENTNAM=BOTH;
    CAT=COMMON;
    VOLTE_TAG=NOT_DEFINED;
    HLR_INDEX=1;
    PS_MSISDNLESS_SUPPORTED=FALSE;
    CS_MSISDNLESS_SUPPORTED=FALSE;
    CSRATTYPE=NO-NO-NO-NO-NO;
    PSRATTYPE=NO-NO-NO-NO-NO;
    ICI=NO;
    STE=NO;
<SUBEND

<SUBBEGIN
    IMSI=xxxxxxxxxxxx;
    MSISDN=xxxxxxxxx;
    DEFCALL=TS11;
    CURRENTNAM=BOTH;
    VOLTE_TAG=NOT_DEFINED;
    HLR_INDEX=1;
    PS_MSISDNLESS_SUPPORTED=FALSE;
    CS_MSISDNLESS_SUPPORTED=FALSE;
    CSRATTYPE=NO-NO-NO-NO-NO;
<SUBEND

这实际上是一条记录,后面是相同格式的多行。我希望输出格式为:

IMSI|MSISDN|DEFCALL|CURRENTNAM|CAT...
xxxx|xxxx|TS11|BOTH|COMMON|COMMON

非常感谢任何帮助。

7 个答案:

答案 0 :(得分:3)

$ cat tst.awk
BEGIN {FS="[=;]"; OFS="|" }
/^<SUB/ {
    if (/END/) {
        print (hdrPrinted++ ? "" : hdr ORS ) rec
        hdr = rec = ""
    }
    next
}
{
    sub(/^[[:space:]]+/,"")
    hdr = (hdr=="" ? "" : hdr OFS) $1
    rec = (rec=="" ? "" : rec OFS) $2
}

$ awk -f tst.awk file
IMSI|MSISDN|DEFCALL|CURRENTNAM|CAT|VOLTE_TAG|HLR_INDEX|PS_MSISDNLESS_SUPPORTED|CS_MSISDNLESS_SUPPORTED|CSRATTYPE|PSRATTYPE|ICI|STE
xxxxxxxxxxxx|xxxxxxxxx|TS11|BOTH|COMMON|NOT_DEFINED|1|FALSE|FALSE|NO-NO-NO-NO-NO|NO-NO-NO-NO-NO|NO|NO

答案 1 :(得分:3)

$ cat test.txt
/<SUBBEGIN/ {f=1; next}      # at start flag up
/<SUBEND/ {                  # at end 
    print b ORS c            # print
    f=0; b=c=""              # flag up and reset variables
} 
f {                          # between markers
    split($1,a,"[=;]")       # gather to 2 variables
    b=b a[1] "|"
    c=c a[2] "|"
}

测试它:

$ awk -f test.awk test.txt
IMSI|MSISDN|DEFCALL|CURRENTNAM|CAT|VOLTE_TAG|HLR_INDEX|PS_MSISDNLESS_SUPPORTED|CS_MSISDNLESS_SUPPORTED|CSRATTYPE|PSRATTYPE|ICI|STE|
xxxxxxxxxxxx|xxxxxxxxx|TS11|BOTH|COMMON|NOT_DEFINED|1|FALSE|FALSE|NO-NO-NO-NO-NO|NO-NO-NO-NO-NO|NO|NO|

答案 2 :(得分:0)

使用tr的解决方法

tr -s '\n' ',' < file > tmpfile;

这给了我

形式的输出
<SUBBEGIN    IMSI=xxxxxxxxxxxx;    MSISDN=xxxxxxxxx;    DEFCALL=TS11;    CURRENTNAM=BOTH;    CAT=COMMON;    VOLTE_TAG=NOT_DEFINED;    HLR_INDEX=1;    PS_MSISDNLESS_SUPPORTED=FALSE;    CS_MSISDNLESS_SUPPORTED=FALSE;    CSRATTYPE=NO-NO-NO-NO-NO;    PSRATTYPE=NO-NO-NO-NO-NO;    ICI=NO; STE=NO; <SUBEND

替换字符串"<SUBBEGIN" with \n

答案 3 :(得分:0)

从这个开始:

sed '/<SUBBEGIN/{:a;N;/\<SUBEND/!ba;s/\n[^=]*=/ /g;s/.*SUBBEGIN//;s/;/|/g}' input

答案 4 :(得分:0)

为简单起见,使用不同的输入文件

$ cat ip.txt 
<SUBBEGIN
    i1=abc;
    i2=ijk;
    i3=xyz;
    k1=NO;
    t1=YES;
<SUBEND

<SUBBEGIN
    i1=foo;
    i2=bar;
    i3=test;
    k1=YES;
    t1=NO;
<SUBEND

$ perl -nle '
$s=/<SUBBEGIN/ if /<SUB/;
if($s && !/<SUB/)
{
    ($k,$v) = /\S+(?==)|=\K[^;]+/g;
    push(@key, $k);
    push(@val, $v);
}
elsif(@key)
{
    print join "|", @key;
    print join "|", @val;
    @key = ();
    @val = ();
}
' ip.txt
i1|i2|i3|k1|t1
abc|ijk|xyz|NO|YES
i1|i2|i3|k1|t1
foo|bar|test|YES|NO
    如果输入行包含$s ,则
  • <SUBBEGIN设置标记
  • 如果设置了标志且输入行不包含<SUB
    • 提取密钥,值对
    • 将它们填入两个不同的数组
  • 输入行再次包含<SUB
    • 检查其中一个数组(例如@key)是否为空
    • 使用|作为分隔符
    • 打印键值数组
    • 清空数组
  • 无论数据结构之间是否有空行,都可以使用

答案 5 :(得分:0)

这是另一种解决方案:

awk脚本

#!/bin/awk

function print_record( hdr )
{
    str = ""

    for( i = 1; i <= 13; i++ )
    {
        if( hdr )
        {
            value = substr( $i, 1, index( $i, "=" ) - 1 )
        }
        else
        {
            value = substr( $i, index( $i, "=" ) + 1 )
        }

        gsub( /^[ \t]+/, "", value )

        if( length(str) > 0 )
            str = str OFS

        str = str value
    }

    print str
}

BEGIN {
    RS="<SUBBEGIN\n"
    FS=";\n"
    hdr=1
    OFS="|"
}

{
    if( index( $0, "=" ) && index( $0, ";" ) )
    {
        if( hdr )
        {
            print_record( 1 )
            hdr = 0;
        }

        print_record( 0 )
    }
}

# eof #

输入文件

<SUBBEGIN
    IMSI=xxxxxxxxxxxx;
    MSISDN=xxxxxxxxx;
    DEFCALL=TS11;
    CURRENTNAM=BOTH;
    CAT=COMMON;
    VOLTE_TAG=NOT_DEFINED;
    HLR_INDEX=1;
    PS_MSISDNLESS_SUPPORTED=FALSE;
    CS_MSISDNLESS_SUPPORTED=FALSE;
    CSRATTYPE=NO-NO-NO-NO-NO;
    PSRATTYPE=NO-NO-NO-NO-NO;
    ICI=NO;
    STE=NO;
<SUBEND
<SUBBEGIN
    IMSI=yyyyyyyyyy;
    MSISDN=yyyyyyyyy;
    DEFCALL=TS11;
    CURRENTNAM=BOTH;
    CAT=COMMON;
    VOLTE_TAG=NOT_DEFINED;
    HLR_INDEX=2;
    PS_MSISDNLESS_SUPPORTED=TRUE;
    CS_MSISDNLESS_SUPPORTED=FALSE;
    CSRATTYPE=NO-YES-NO-NO-NO;
    PSRATTYPE=NO-NO-NO-YES-NO;
    ICI=NO;
    STE=NO;
<SUBEND
<SUBBEGIN
    IMSI=zzzzzzzzzz;
    MSISDN=zzzzzzzzzzzzzzz;
    DEFCALL=TS11;
    CURRENTNAM=BOTH;
    CAT=COMMON;
    VOLTE_TAG=NOT_DEFINED;
    HLR_INDEX=3;
    PS_MSISDNLESS_SUPPORTED=FALSE;
    CS_MSISDNLESS_SUPPORTED=TRUE;
    CSRATTYPE=NO-YES-YES-NO-NO;
    PSRATTYPE=NO-NO-YES-YES-NO;
    ICI=YES;
    STE=YES;
<SUBEND

<强>输出

$ awk -f script.awk -- input.txt
IMSI|MSISDN|DEFCALL|CURRENTNAM|CAT|VOLTE_TAG|HLR_INDEX|PS_MSISDNLESS_SUPPORTED|CS_MSISDNLESS_SUPPORTED|CSRATTYPE|PSRATTYPE|ICI|STE
xxxxxxxxxxxx|xxxxxxxxx|TS11|BOTH|COMMON|NOT_DEFINED|1|FALSE|FALSE|NO-NO-NO-NO-NO|NO-NO-NO-NO-NO|NO|NO
yyyyyyyyyy|yyyyyyyyy|TS11|BOTH|COMMON|NOT_DEFINED|2|TRUE|FALSE|NO-YES-NO-NO-NO|NO-NO-NO-YES-NO|NO|NO
zzzzzzzzzz|zzzzzzzzzzzzzzz|TS11|BOTH|COMMON|NOT_DEFINED|3|FALSE|TRUE|NO-YES-YES-NO-NO|NO-NO-YES-YES-NO|YES|YES

希望它有帮助!

答案 6 :(得分:0)

使用unix工具链,也许是最短的...

$  sed '/^</d' file | tr '=' '\n' | tr -d ' ;' | pr -13ts'|'

IMSI|MSISDN|DEFCALL|CURRENTNAM|CAT|VOLTE_TAG|HLR_INDEX|PS_MSISDNLESS_SUPPORTED|CS_MSISDNLESS_SUPPORTED|CSRATTYPE|PSRATTYPE|ICI|STE
xxxxxxxxxxxx|xxxxxxxxx|TS11|BOTH|COMMON|NOT_DEFINED|1|FALSE|FALSE|NO-NO-NO-NO-NO|NO-NO-NO-NO-NO|NO|NO