Bash의 중첩된 괄호에서 데이터 추출

Bash의 중첩된 괄호에서 데이터 추출

감사 및 마이그레이션을 위해 특정 데이터를 추출하고 파일에 저장하는 방법이 필요했습니다. 내 데이터는 다음과 같습니다.

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 파일로 출력을 생성하고 감사를 위해 열 수 있습니다.

여기에 이미지 설명을 입력하세요

입력 데이터 및 요구사항 업데이트 중(죄송합니다),MTU가 없는 더미 VLAN이 있다는 것을 알게 되면 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-- 해당 데이터는 유효한 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"

또는 설치tcllibCSV 출력을 처리하도록 하려면 다음을 수행합니다.

#!/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
}

다양한 네트워크 유형과 "없음" 값을 처리하고 필드 순서가 올바른지 확인하려면 다음을 수행하세요.

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 '
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

관련 정보