Intercambiar líneas incrementalmente entre dos patrones Regex en un archivo

Intercambiar líneas incrementalmente entre dos patrones Regex en un archivo

Estoy intentando procesar un texto en un archivo usando un script bash. El objetivo es tomar todas las líneas que comienzan con "campo:" sangradas bajo una etiqueta 'atributo:' e intercambiarlas con la línea asociada que comienza con "- attr:" que sigue.

Hasta ahora creo que tengo patrones de expresiones regulares que deberían coincidir con las etiquetas:

/ *field:(.*)/g

/ *- attr:(.*)/g

Pero no he tenido éxito con la lógica para analizar los campos deseados y hacer que se intercambien correctamente.

Texto de entrada de ejemplo

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

Salida deseada

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

¿Cómo haría para lograr esto?

Respuesta1

Usando cualquier awk en cualquier shell en cada caja 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'

Si es posible que no tenga un espacio después field:en algunas líneas o simplemente tenga un deseo ardiente de usar una expresión regular por algún motivo, cambie $1=="field:"a $1~/^field:/o /^[[:space:]]*field:/, lo que prefiera.

Respuesta2

Con sed:

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

Si hacemos coincidir una fieldpalabra clave entonces:

  • guardar la línea actual en hold space( h)
  • obtener la siguiente línea del archivo en pattern space( n)
  • intercambie el pattern spacecon el hold space( G) (Equivale al intercambio de línea)

Imprime cada línea que encuentres:p

Respuesta3

Usando awk:

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

En este comando, si field:se encuentra, el registro de entrada actual ( $0) se guarda en la variable ay x se establece en cero. Y si attr:se encuentra, $0se cambia d a antiguo $0seguido de ORS(nueva línea) seguido de variable a.

Respuesta4

Podemos usar construcciones sed POSIX para invertir dichas líneas.

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

información relacionada