Como dividir um arquivo com base no contexto?

1

Eu tenho alguns arquivos que contêm os resultados do comando lldpneighbors de todos os nossos servidores. Eu gostaria de dividir esses arquivos em arquivos individuais para cada servidor, a fim de facilitar a importação desses dados em nosso sistema de inventário.

Entrada de amostra

=== 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: 

Isto é aproximadamente o que todos os resultados parecem com alguma variação (Eles não são todos do mesmo tamanho, alguns são várias linhas mais longas por causa de mais interfaces). A string de delimitação na qual gostaria de corresponder é:

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

Idealmente, gostaria que cada arquivo fosse nomeado como hostname (isso seria conveniente e não é necessário), portanto, os resultados acima seriam divididos em arquivos como:

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: 

Estou tentando usar csplit para realizar isso, mas não consigo corresponder ao regex por algum motivo. Os comandos que experimentei:

$ 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

Alguma sugestão?

    
por Jesse_b 24.08.2017 / 17:44

2 respostas

2
Solução

awk :

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

Cada arquivo será nomeado de acordo com hostname ( SERVERNAME<number> )

  • /^===/ - ao encontrar a linha que começa com ===

  • fn=substr($NF,2,length($NF)-3) - construindo o nome do arquivo fn , substr($NF,2,length($NF)-3) - extrairá o nome do host ignorando parênteses em torno dele ( $NF - last field)

  • print > fn - imprima a linha subjacente no arquivo
por 24.08.2017 / 18:28
1

Não especifique em excesso a expressão regular:

$ csplit logfile '/^===/'

Isso cria xx00 para a primeira seção e xx01 para a segunda.

Como alternativa, se você tiver outras linhas iniciadas com === que você não deseja dividir:

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

Para substituir xx por outra string fixa, use -p (a string não pode ser retirada dos dados de entrada, infelizmente).

    
por 24.08.2017 / 18:23