bash脚本如何将带密钥的日志转换为csv

时间:2013-12-14 23:26:10

标签: bash csv

我有一个像表格一样的日志

ge-1/0/0.0              up    down inet     10.100.100.1/24 
                                   multiservice
ge-1/0/2.107            up    up   inet     10.187.132.193/27
                                            10.187.132.194/27
                                   multiservice
ge-1/1/4                up    up  
ge-1/1/5.0              up    up   inet     10.164.69.209/30
                                   iso     
                                   mpls    
                                   multiservice

我们如何将其转换为格式化csv,如下所示:

ge-1/0/0.0,up,down,inet|multiservice,10.100.100.1/24
ge-1/0/2.107,up,up,inet|multiservice,"10.187.132.193/27,10.187.132.194/27"
ge-1/1/4,up,up
ge-1/1/5.0,up,up,inet|iso|mpls|multiservice,10.164.69.209/30

我尝试使用grep interfacename -A4,但它显示了其他界面信息。

2 个答案:

答案 0 :(得分:3)

#!/bin/bash

show() {
    [ "$ge" ] || return
    [ "$add_quotes" ] && iprange="\"$iprange\""
    out="$ge,$upd1,$upd2,$service,$iprange"
    out="${out%%,}"
    echo "${out%%,}"
}

while read line
do 
    case "$line" in
        ge*)
            show
            read ge upd1 upd2 service iprange < <( echo "$line" )
            add_quotes=
            ;;
        [0-9]*)
            iprange="$iprange,$line"
            add_quotes=Y
            ;;
        *) 
            service="$service|$line"
            ;;
    esac
done

# Show last line
show

将您的示例数据作为stdin提供,此脚本将返回:

ge-1/0/0.0,up,down,inet|multiservice,10.100.100.1/24
ge-1/0/2.107,up,up,inet|multiservice,"10.187.132.193/27,10.187.132.194/27"
ge-1/1/4,up,up
ge-1/1/5.0,up,up,inet|iso|mpls|multiservice,10.164.69.209/30

工作原理:此脚本逐行读取stdin(while read line)。然后将每一行分为三种类型之一:(a)新记录(即以“ge-”开头的行),(b)提供另一IP范围的连续记录(即以数字开头的记录) ),或(c)提供另一项服务的延续行(即以字母开头的记录)。依次采取这些案例:

(a)当该行包含新记录的开头时,表示前一记录已结束,因此我们使用show函数将其打印出来。然后我们从新行读取我命名的五列:ge upd1 upd2 service iprange。并且,我们将add_quotes变量重置为空。

(b)当该行仅包含另一个IP范围时,我们将其添加到当前IP范围。根据问题中的示例,两个或多个IP范围的组合用逗号分隔并用引号括起来。因此,我们将add_quotes设置为“Y”。

(c)当该行包含附加服务时,我们将其添加到服务变量中。根据问题中的示例,两个服务由竖线“|”分隔并且没有使用引号。

函数show首先检查以确保通过检查ge变量是否为空来显示要显示的记录。如果它为空,则执行return语句,以便函数退出(返回)而不处理任何其他语句。如果$ge非空,则函数将继续执行下一个语句,如果需要,它将在IP范围变量周围添加引号。然后它将变量与用逗号分隔的变量组合起来,删除尾随逗号(根据问题中的示例),并将结果发送到stdout。

答案 1 :(得分:1)

parselog.awk

#!/usr/bin/gawk -f

BEGIN {
    RS = "[^\n]*\n( [^\n]*\n)*"
    OFS = ","
}

length(RT) > 0 {
    $0 = RT     # See: http://stackoverflow.com/a/11917783/27581

    opts = ""
    ips = ""
    for (i = 4; i <= NF; ++i) {
        if (isIP($i)) {
            ips = append(ips, $i, ",")
        } else {
            opts = append(opts, $i, "|")
        }
    }
    print $1, $2, $3, opts, "\"" ips "\""
}

function isIP(str) {
    return str ~ /^[0-9]/
}

function append(list, val, separator) {
    if (length(list) > 0) {
        list = list separator
    }
    return list val
}

用法

$ ./parselog.awk < log.txt 
ge-1/0/0.0,up,down,inet|multiservice,"10.100.100.1/24"
ge-1/0/2.107,up,up,inet|multiservice,"10.187.132.193/27,10.187.132.194/27"
ge-1/1/4,up,up,,""
ge-1/1/5.0,up,up,inet|iso|mpls|multiservice,"10.164.69.209/30"