Zeilen zwischen zwei Regex-Mustern in einer Datei inkrementell austauschen

Zeilen zwischen zwei Regex-Mustern in einer Datei inkrementell austauschen

Ich versuche, mithilfe eines Bash-Skripts eine Textverarbeitung für eine Datei durchzuführen. Ziel ist es, alle Zeilen, die mit „field:“ beginnen und unter der Bezeichnung „attribute:“ eingerückt sind, mit der zugehörigen Zeile zu ersetzen, die mit „- attr:“ beginnt und folgt.

Bisher glaube ich, dass ich Regex-Muster habe, die mit den Beschriftungen übereinstimmen sollten:

/ *field:(.*)/g

/ *- attr:(.*)/g

Aber ich hatte keinen Erfolg mit der Logik, die gewünschten Felder zu analysieren und sie richtig zu vertauschen.

Beispiel-Eingabetext

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

Gewünschte Ausgabe

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

Wie würde ich das erreichen?

Antwort1

Verwenden eines beliebigen awk in einer beliebigen Shell auf jeder Unix-Box:

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

Wenn Ihnen nach einigen Zeilen ein Leerzeichen fehlt field:oder Sie aus irgendeinem Grund unbedingt einen regulären Ausdruck verwenden möchten, ändern Sie ihn $1=="field:"in $1~/^field:/oder /^[[:space:]]*field:/, je nachdem, was Sie bevorzugen.

Antwort2

Mit sed:

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

Wenn ein Schlüsselwort übereinstimmt field, dann:

  • speichert die aktuelle Zeile im hold space( h)
  • Holen Sie sich die nächste Zeile aus der Datei im pattern space( n)
  • vertausche das pattern spacemit dem hold space( G) (entspricht Zeilentausch)

Drucken Sie jede Zeile aus, die Sie finden:p

Antwort3

Verwendung von awk:

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

Wenn in diesem Befehl field:gefunden wird, wird der aktuelle Eingabedatensatz ( $0) in der Variable gespeichert aund x wird auf Null gesetzt. Und wenn attr:gefunden wird, $0wird d in alt geändert, $0gefolgt von ORS(neue Zeile), gefolgt von der Variable a.

Antwort4

Wir können POSIX-Sed-Konstrukte verwenden, um die besagten Zeilen umzudrehen.

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

verwandte Informationen