Extraer datos del paréntesis anidado en bash

Extraer datos del paréntesis anidado en bash

Necesitaría una forma de extraer ciertos datos y almacenarlos en un archivo para auditoría y migración. Aquí están mis datos.

network vlan internal-vlan {
    description "internal-use"
    interfaces {
        1.1 { }
        1.2 { }
    }
    MTU {
    1500
    }
}
network vlan external-vlan {
    description "external-use"
    interfaces {
       2.1 { }
       2.2 { }
    }
    MTU {
    1500
    }
}

Necesito extraer los nombres de VLAN y sus descripciones y los detalles de su interfaz en un formato de tabla, algo como lo siguiente. Si pudiera ejecutar un script bash o tal vez perl a través de este archivo de datos, generaré el resultado en un archivo csv y podría abrirlo para auditarlo.

ingrese la descripción de la imagen aquí

Actualizando los datos de entrada y el requisito (LO SENTIMOS),Si observa que hay una VLAN ficticia que no tiene MTU, quiero que el valor de las columnas MTU sea ninguno.

network vlan internal-vlan {
    description "internal-use"
    interfaces {
        1.1 { }
        1.2 { }
    }
    MTU {
    1500
    }
}
network vlan external-vlan {
    description "external-use"
    interfaces {
       2.1 { }
       2.2 { }
    }
    MTU {
    1500
    }
}
network vlan dummy-vlan {
    description "dummy-use"
    interfaces {
       1.1 { }
    }
}
network interface 1.1 {
    Status {
        UP
    }
}
network interface 1.2 {
    Status {
        UP
    }
}
network interface 2.1 {
    Status {
        DOWN
    }
}
network interface 2.2 {
    Status {
        UP
    }
}

ingrese la descripción de la imagen aquí

Respuesta1

En realidad, este es un uso perfecto paratcl-- esos datos tienen una sintaxis Tcl válida, por lo que solo necesitamos definir una networkfunción y tendremos un DSL válido:

#!/usr/bin/env tclsh

proc network {_ name data} {
    set values [lmap val [concat $name [dict values $data]] {
        format {"%s"} [regsub -all {\s+} [string trim $val] " "]
    }]
    puts [join $values ,]
}

puts {"Vlan","Description","Interfaces","MTU"}
source [lindex $argv 0]

entonces

$ tclsh parse.tcl datafile
"Vlan","Description","Interfaces","MTU"
"internal-vlan","internal-use","1.1 { } 1.2 { }","1500"
"external-vlan","external-use","2.1 { } 2.2 { }","1500"

O instalartcllibpara permitirle manejar la salida CSV:

#!/usr/bin/env tclsh
package require csv

proc network {_ name data} {
    puts [csv::join [lmap val [concat $name [dict values $data]] {
        regsub -all {\s+} [string trim $val] " "
    }]]
}

puts [csv::join {Vlan Description Interfaces MTU}]
source [lindex $argv 0]
$ tclsh parse.tcl datafile
Vlan,Description,Interfaces,MTU
internal-vlan,internal-use,1.1 { } 1.2 { },1500
external-vlan,external-use,2.1 { } 2.2 { },1500

Para la versión anterior de Tcl 8.5, agregue este proceso en la parte superior del programa:

proc lmap {varname list body} {
    upvar 1 $varname element
    set result {}
    foreach element $list {
        lappend result [uplevel 1 $body]
    }
    return $result
}

Para manejar diferentes tipos de redes, así como el valor "ninguno", y también para garantizar que los campos estén en el orden correcto:

proc network {type name data} {
    if {$type ne "vlan"} {
        return
    }
    set values [list $name]
    foreach key {description interfaces MTU} {
        set val [expr {[dict exists $data $key] ? [dict get $data $key] : "none"}]
        lappend values [regsub -all {\s+} [string trim $val] " "]
    }
    puts [join $values ,]
}

Respuesta2

Si sus datos de entrada son uniformes, puede intentar algo como lo siguiente:

#! /usr/bin/perl
use strict;
use warnings;
use feature qw{ say };

say 'Vlan,Description,Interfaces,MTU';
my @interfaces;
while (<>) {
    if (/(?|network vlan (.*) \{|description (".*"))/) {
        print "$1,";
    } elsif (/interfaces/) {
        @interfaces = ();
    } elsif (/ *(.* \{ \})/) {
        push @interfaces, "$1";
    } elsif (/MTU \{/) {
        my $next = <>;
        say "@interfaces,$1" if $next =~ /^ *(.*)/;
    }
}

Si se permite una mayor variación en los datos (es decir, las nuevas líneas son opcionales), tendrá que escribir un analizador real.

Respuesta3

Siempre que el formato del archivo de configuración sea similar para todas las configuraciones:
Usandoawk:

$ awk '
BEGIN { printf "Vlan,descripton,interfaces,MTU\n" }
{
if ($1 ~ /^network/ ) { printf $3","; }
if ( $1 ~ /description/ ) { printf $2","; }
if ( $1 ~ /^[0-9]\.[0-9]/ ) { printf $1$2$3" "; }
if ( $1 ~ /^[0-9]{2,}/ ) { printf ","$1"\n"; }
} ' input.conf
Vlan,descripton,interfaces,MTU
internal-vlan,"internal-use",1.1{} 1.2{} ,1500
external-vlan,"external-use",2.1{} 2.2{} ,1500

información relacionada