从Shell中的文件中提取字段

时间:2017-03-20 18:05:10

标签: shell awk

我在文件中有很多数据,如下所示

 alert tcp any any -> any any (msg: "test1"; sid:16521; rev:1;created_at 2010_07_30, updated_at 2016_07_01;)
 alert tcp any any -> any any (msg: "test2"; nocase; sid :23476;distance:0; rev:1;created_at 2010_10_30, updated_at 2013_07_11;)
 alert tcp any any -> any any (msg: "test3"; sid:236487; file_data; content:"clsid"; nocase; distance:0; created_at 2008_08_03, updated_at 2016_05_01;

我想从文件&中提取sid,msg,created_at和updated_at。输出应该看起来像

test1 | 16521 | 2010_07_30 | 2016_07_01
test2 | 23476 | 2010_10_30 | 2013_07_11
test3 | 236487| 2008_08_03 | 2016_05_01

我使用的脚本是

cat $file  | grep -v "^#" | grep "^alert" | sed 's/\"//g' | awk -F ';' '
{
        for(i=1;i<=NF;i++)
    {
            if (match($i,"sid:")>0)
        {
            split($i, array1, ":")
            Rule_sid=array1[2]
                    }
            if(match($i,"msg:")>0)
                    {
                        split($i, array, "(")
            split(array[2], array2, ":")
                        message=array2[2]
                    }
            if(match($i,/metadata:/)>0 )
        {
            split($i, array3,/created_at/)
            create_date=array3[2]
        }
            if(match($i,/metadata:/)>0 )
                    {
                        split($i, array4, ", updated_at ")
            update_date=array4[2]
                    }


           }
            print Rule_sid "|" message "|" create_date "|" update_date
    }' >> Rule_Files/$file

2 个答案:

答案 0 :(得分:0)

对于初学者,您可以使用sed

提取带有正则表达式的字段
sed '/^alert/s/^.*msg[: ]*"\([^"]*\)".*sid[: ]*\([0-9][0-9]*\);.*created_at *\([^,]*\),.*updated_at *\([0-9_][0-9_]*\).*$/\1|\2|\3|\4/' $file

这给你输出如下:

test1|16521|2010_07_30|2016_07_01
test2|23476|2010_10_30|2013_07_11
test3|236487|2008_08_03|2016_05_01

现在你想要很好地排成一列,你必须把它喂给别的东西,也许是awk:

sed '/^alert/s/^.*msg[: ]*"\([^"]*\)".*sid[: ]*\([0-9][0-9]*\);.*created_at *\([^,]*\),.*updated_at *\([0-9_][0-9_]*\).*$/\1|\2|\3|\4/' $file |
awk -F\|  'BEGIN { OFS="| " } {$2=sprintf("%6d",$2)}1'

这给了你:

test1|  16521| 2010_07_30| 2016_07_01
test2|  23476| 2010_10_30| 2013_07_11
test3| 236487| 2008_08_03| 2016_05_01

如果你必须处理任意宽的列值并且仍然想要垂直对齐,那么你必须首先编写一些处理所有行的东西,以便在打印任何东西之前找到每个行的最大值。这是我留给读者的一个练习。

答案 1 :(得分:0)

使用awk

根据您的兴趣修改-v OFS=" | "-v extract="msg,sid,created_at,updated_at"OFS是输出字段分隔符,变量extract包含需要解析的字段列表(以逗号分隔) ,如果找不到任何字段,它将给出Null

程序假定当前字段匹配旁边存在字段值,假设sid时找到字段j=4,其值j+1位于j=5

<强>输入

$ cat file
 alert tcp any any -> any any (msg: "test1"; sid:16521; rev:1;created_at 2010_07_30, updated_at 2016_07_01;)
 alert tcp any any -> any any (msg: "test2"; nocase; sid :23476;distance:0; rev:1;created_at 2010_10_30, updated_at 2013_07_11;)
 alert tcp any any -> any any (msg: "test3"; sid:236487; file_data; content:"clsid"; nocase; distance:0; created_at 2008_08_03, updated_at 2016_05_01;)

<强>输出

$ awk -v OFS=" | " -v extract="msg,sid,created_at,updated_at" '
 BEGIN{
    split(extract,Fields,/,/)
 }
 {
    gsub(/[:";,()]/," "); 
    s=""; 
    for(i=1; i in Fields; i++)
    { 
        f = 1
        for(j=1; j<=NF; j++)
        { 
            if($j==Fields[i])
            {
              f = 0 
              s = ( s ? s OFS :"") $(j+1) 
              break 
            } 
        }
        if(f){
            s = (s ? s OFS:"") "Null"
        }     
     } 
        print s 
 }' file

test1 | 16521 | 2010_07_30 | 2016_07_01
test2 | 23476 | 2010_10_30 | 2013_07_11
test3 | 236487 | 2008_08_03 | 2016_05_01