【问题标题】:bash scripting how convert log with key into csvbash脚本如何将带有密钥的日志转换为csv
【发布时间】:2013-12-14 23:26:09
【问题描述】:

我有一个格式类似于表格的日志

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 试过了,但它会显示其他接口信息。

【问题讨论】:

    标签: bash csv


    【解决方案1】:
    #!/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
    

    将您的示例数据作为标准输入提供,此脚本返回:

    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
    

    工作原理:此脚本逐行从标准输入 (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 范围变量周围添加引号。然后它将变量用逗号分隔,删除尾随逗号(根据问题中的示例),并将结果发送到标准输出。

    【讨论】:

    • 就像我得到的一样,这个脚本尝试逐行获取,当它遇到 ge* 接口时,它会处理,还有 IP 地址 [0-9]。你能解释一下为什么我们使用 add_quotes =Y?
    • 我已经添加了很长的解释。至于在 IP 范围周围添加引号的决定,它只是遵循问题中的示例输出:当两个 IP 范围用逗号组合在一起时,IP 范围 除外 周围没有引号。
    【解决方案2】:

    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"
    

    【讨论】:

      猜你喜欢
      • 2019-02-16
      • 1970-01-01
      • 2017-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-11
      相关资源
      最近更新 更多