Troca incremental de linhas entre dois padrões Regex em um arquivo

Troca incremental de linhas entre dois padrões Regex em um arquivo

Estou tentando fazer algum processamento de texto em um arquivo usando um script bash. O objetivo é pegar todas as linhas que começam com "field:" recuadas sob um rótulo 'attribute:' e trocá-las pela linha associada que começa com "- attr:" a seguir.

Até agora acho que tenho padrões regex que devem corresponder aos rótulos:

/ *field:(.*)/g

/ *- attr:(.*)/g

Mas não tive sucesso com a lógica para analisar os campos desejados e fazer com que eles trocassem corretamente.

Exemplo de texto de entrada

- metric: 'example.metric.1'
  attributes:
      field: 'example 1'
    - attr: 'example1'
      field: 'example 2'
    - attr: 'example2'
      field: 'example 3'
    - attr: 'example3'
      field: 'example 4'
    - attr: 'example4'
- metric: 'example.metric.2'
  attributes:
      field: 'example 5'
    - attr: 'example5'
      field: 'example 6'
    - attr: 'example6'
      field: 'example 7'
    - attr: 'example7'
- metric: 'example.metric.3'
...

Saída Desejada

- metric: 'example.metric.1'
  attributes:
    - attr: 'example1'
      field: 'example 1'
    - attr: 'example2'
      field: 'example 2'
    - attr: 'example3'
      field: 'example 3'
    - attr: 'example4'
      field: 'example 4'
- metric: 'example.metric.2'
  attributes:
    - attr: 'example5'
      field: 'example 5'
    - attr: 'example6'
      field: 'example 6'
    - attr: 'example7'
      field: 'example 7'
- metric: 'example.metric.3'
... 

Como eu faria para conseguir isso?

Responder1

Usando qualquer awk em qualquer shell em cada caixa Unix:

$ awk '$1=="field:"{s=ORS $0; next} {print $0 s; s=""}' file
- metric: 'example.metric.1'
  attributes:
    - attr: 'example1'
      field: 'example 1'
    - attr: 'example2'
      field: 'example 2'
    - attr: 'example3'
      field: 'example 3'
    - attr: 'example4'
      field: 'example 4'
- metric: 'example.metric.2'
  attributes:
    - attr: 'example5'
      field: 'example 5'
    - attr: 'example6'
      field: 'example 6'
    - attr: 'example7'
      field: 'example 7'
- metric: 'example.metric.3'

se você não tiver um espaço depois field:de algumas linhas ou apenas tiver um desejo ardente de usar um regexp por algum motivo, mude $1=="field:"para $1~/^field:/ou /^[[:space:]]*field:/, o que preferir.

Responder2

Com sed:

sed -n '/^ *field: /{h;n;G};p' data

Se correspondermos a uma fieldpalavra-chave, então:

  • salve a linha atual no hold space( h)
  • obtenha a próxima linha do arquivo no pattern space( n)
  • troque o pattern spacepor hold space( G) (igual à troca de linha)

imprima cada linha que você encontrar:p

Responder3

Usando awk:

awk '{if ($1 == "field:") {a=$0;x=0} 
else if (/- attr:/) {$0 = $0 ORS a; x=1} else {x=1}}x' input

Neste comando, se field:for encontrado, o registro de entrada atual ( $0) será salvo na variável ae x será definido como zero. E se attr:for encontrado, $0altere d para old $0seguido de ORS(nova linha) seguido de variável a.

Responder4

Podemos usar construções POSIX sed para inverter as referidas linhas.

sed '/attr:/!x;$G' file

informação relacionada