Мне нужен способ извлечь определенные данные и сохранить их в файле для аудита и миграции. Вот как выглядят мои данные.
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
}
}
Мне нужно извлечь имена vlan и их описания, а также детали интерфейса в табличном формате, что-то вроде ниже. Если бы я мог скрипт bash или, может быть, perl для запуска этого файла данных, я бы сгенерировал вывод в файле csv и мог бы открыть его для аудита.
Обновление входных данных и требований (ИЗВИНИТЕ),Если вы заметили, что есть фиктивная VLAN, у которой нет MTU, то я хочу, чтобы значение столбца MTU было нулевым.
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
}
}
решение1
На самом деле это идеальное применение дляТсл-- эти данные являются допустимым синтаксисом Tcl, поэтому нам просто нужно определить network
функцию, и у нас будет допустимый DSL:
#!/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]
затем
$ 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"
Или установитеtcllibчтобы позволить ему обрабатывать вывод 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
Для более старой версии Tcl 8.5 добавьте эту процедуру в начало программы:
proc lmap {varname list body} {
upvar 1 $varname element
set result {}
foreach element $list {
lappend result [uplevel 1 $body]
}
return $result
}
Для обработки различных типов сетей, а также значения «none», а также для обеспечения правильного порядка полей:
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 ,]
}
решение2
Если ваши входные данные однородны, вы можете попробовать что-то вроде следующего:
#! /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 =~ /^ *(.*)/;
}
}
Если допускается больше вариаций данных (т.е. символы новой строки необязательны), вам придется написать настоящий парсер.
решение3
При условии, что формат файла конфигурации одинаков для всех конфигураций:
Использованиеawk:
$ 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