web-dev-qa-db-ja.com

コンテキストに基づいてファイルを分割する方法は?

すべてのサーバーからのlldpneighborsコマンドの結果を含むファイルがいくつかあります。このデータを在庫システムに簡単にインポートできるように、これらのファイルをサーバーごとに個別のファイルに分割したいと思います。

サンプル入力

=== Output from 00000000-0000-0000-0000-000000000000 (SERVERNAME1):
Interface 'ixgbe0' has 1 LLDP Neighbors: 
Neighbor 1:
    Chassis ID:         MAC Address - 00 01 02 03 04 05 
    Port ID:        Interface Name - TenGigabitEthernet 0/6
    Time To Live:       120 seconds
    System Name:        name-of-switch-01
    End Of LLDPDU:  
Interface 'igb0' has 1 LLDP Neighbors: 
Neighbor 1:
    Chassis ID:         MAC Address - 00 01 02 03 04 05 
    Port ID:        Interface Name - TenGigabitEthernet 0/23
    Time To Live:       120 seconds
    System Name:        name-of-switch-02
    End Of LLDPDU:  
=== Output from 00000000-0000-0000-0000-000000000000 (SERVERNAME2):
Interface 'ixgbe0' has 1 LLDP Neighbors: 
Neighbor 1:
    Chassis ID:         MAC Address - 00 01 02 03 04 05 
    Port ID:        Interface Name - TenGigabitEthernet 0/2
    Time To Live:       120 seconds
    System Name:        name-of-switch-01
    End Of LLDPDU:  
Interface 'igb0' has 1 LLDP Neighbors: 
Neighbor 1:
    Chassis ID:         MAC Address - 00 01 02 03 04 05 
    Port ID:        Interface Name - TenGigabitEthernet 0/19
    Time To Live:       120 seconds
    System Name:        name-of-switch-02
    End Of LLDPDU: 

これはおおよそすべての結果がいくつかのバリエーションでどのように見えるかです(それらはすべて同じ長さではなく、いくつかはより多くのインターフェースのために数行長くなります)。照合したい区切り文字列は次のとおりです。

=== Output from [UUID] ([HOSTNAME]):

理想的には、各ファイルにホスト名という名前を付けたいので(これは単に便利で必要ではありません)、上記の結果は次のようなファイルに分割されます。

SERVERNAME1

=== Output from 00000000-0000-0000-0000-000000000000 (SERVERNAME1):
Interface 'ixgbe0' has 1 LLDP Neighbors: 
Neighbor 1:
    Chassis ID:         MAC Address - 00 01 02 03 04 05 
    Port ID:        Interface Name - TenGigabitEthernet 0/6
    Time To Live:       120 seconds
    System Name:        name-of-switch-01
    End Of LLDPDU:  
Interface 'igb0' has 1 LLDP Neighbors: 
Neighbor 1:
    Chassis ID:         MAC Address - 00 01 02 03 04 05 
    Port ID:        Interface Name - TenGigabitEthernet 0/23
    Time To Live:       120 seconds
    System Name:        name-of-switch-02
    End Of LLDPDU: 

SERVERNAME2

=== Output from 00000000-0000-0000-0000-000000000000 (SERVERNAME2):
Interface 'ixgbe0' has 1 LLDP Neighbors: 
Neighbor 1:
    Chassis ID:         MAC Address - 00 01 02 03 04 05 
    Port ID:        Interface Name - TenGigabitEthernet 0/2
    Time To Live:       120 seconds
    System Name:        name-of-switch-01
    End Of LLDPDU:  
Interface 'igb0' has 1 LLDP Neighbors: 
Neighbor 1:
    Chassis ID:         MAC Address - 00 01 02 03 04 05 
    Port ID:        Interface Name - TenGigabitEthernet 0/19
    Time To Live:       120 seconds
    System Name:        name-of-switch-02
    End Of LLDPDU: 

これを達成するためにcsplitを使用しようとしていますが、何らかの理由で正規表現を一致させることができません。私が試したコマンド:

$ csplit jbutryn_us-west-a_neighbors %===.*:% '{20}'
csplit: ===.*:: no match

$ csplit jbutryn_us-west-a_neighbors /===.*:/ '{20}'
552
552
552
csplit: ===.*:: no match

$ csplit jbutryn_us-west-a_neighbors '/===.*:/' '{20}'
552
552
552
csplit: ===.*:: no match

$ csplit -ks -f test jbutryn_us-west-a_neighbors '/===.*:/' '{20}'
csplit: ===.*:: no match

助言がありますか?

1
jesse_b

awk解決策:

_awk '/^===/{ fn=substr($NF,2,length($NF)-3) }{ print > fn }' file
_

各ファイルには、hostname(_SERVERNAME<number>_)に従って名前が付けられます。

  • _/^===/_-_===_で始まる行に遭遇したとき

  • fn=substr($NF,2,length($NF)-3)-ファイル名の作成fnsubstr($NF,2,length($NF)-3)-周囲の括弧を無視してホスト名を抽出します(_$NF_-最後のフィールド)

  • _print > fn_-基になる行をファイルに出力します
2
RomanPerekhrest

正規表現を指定しすぎないでください。

$ csplit logfile '/^===/'

これにより、最初のセクションにxx00が作成され、2番目のセクションにxx01が作成されます。

または、===で始まる他の行があり、しない分割したい場合:

$ csplit logfile '/^=== Output from/'

xxを別の固定文字列に置き換えるには、-pを使用します(残念ながら、入力データから文字列を取得することはできません)。

1
Kusalananda