Text-Processing

從bash中的嵌套括號中提取數據

  • April 15, 2020

我需要一種方法來提取某些數據並將其儲存在文件中以進行審計和遷移。這是我的數據樣子。

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

在此處輸入圖像描述

這實際上是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"

或者安裝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 添加到程序頂部:

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 ,]
}

引用自:https://unix.stackexchange.com/questions/580031