Wie ändere ich das Spaltenformat der ersten Zeilen im nächsten, ersetze * durch eine Zahl und führe Operationen zwischen Spalten durch?

Wie ändere ich das Spaltenformat der ersten Zeilen im nächsten, ersetze * durch eine Zahl und führe Operationen zwischen Spalten durch?

Ich habe die folgende Datei, in der die ersten beiden Zeilen wie eine einzelne Spalte (also eine fortlaufende Zeichenfolge) dargestellt sind. Ich möchte sie in Spalten aufteilen und das Zeichen „*“ durch eine Zahl „x“ ersetzen, die die wissenschaftliche Notation und das Spaltenformat als vierte und fünfte Zeile angibt.

0.001000000*********************************************
0.061059059-3524.927327218-3524.938421865***************
0.121118118 -887.564833130 -887.569649256-6250.350946527
0.181177177 -387.169559377 -387.173137963-2743.981985633
0.241236236 -223.812193853 -223.815321341-1504.799155086
0.301295295 -134.073058536 -134.075910507 -924.916305653
0.361354354  -76.668692929  -76.671412688 -612.480371134

Beachten Sie, dass die Zeilen 1, 2 und 3 dasselbe Problem haben, nämlich 2 aufeinanderfolgende Spalten, als ob es sich um eine einzelne Spalte handeln würde (ich möchte ein Leerzeichen zwischen ihnen einfügen). Ich möchte auch eine komplexe Operation wie sqrt((sqrt($2 ^ 2 + $4 ^ 2) + $2) / 2) zwischen den Spalten ausführen.

Erwartete Ergebnisse:

0.001000000 -3524.927327218 -3524.938421865 -6250.350946527
0.061059059 -3524.927327218 -3524.938421865 -6250.350946527
0.121118118  -887.564833130  -887.569649256 -6250.350946527
0.181177177  -387.169559377  -387.173137963 -2743.981985633
0.241236236  -223.812193853  -223.815321341 -1504.799155086
0.301295295  -134.073058536  -134.075910507  -924.916305653
0.361354354   -76.668692929   -76.671412688  -612.480371134

Ich würde gerne wissen, ob es eine Lösung für mein Problem gibt.

Antwort1

Mir scheint, Sie haben zwei sehr unterschiedliche Probleme:

  • Unvollständige Zeilen, die Sie ausfüllen müssen
  • Zahlen, die ohne Trennzeichen angehängt werden

Obwohl dies wahrscheinlich mit einem einzigen Awk-Aufruf machbar ist, würde ich der Einfachheit halber für jeden Task einen Aufruf verwenden.

Aufgrund Ihrer Beispiele für Ein- und Ausgaben gehe ich davon aus, dass Ihre Zahlen immer 9 Dezimalstellen haben.

Umgang mit dem Problem „Kein Trennzeichen“

awk '{
         while ($0 ~ /[0-9]+\.[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][^ ]/) {
             $0=gensub(/([0-9]+\.[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])([^ ])/, "\\1 \\2", $0)
        }
        print
      }' input.txt > first_step.txt

Hinweis: Wenn Ihre gawkVersion >= 4.0 ist, können Sie [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]durch ersetzen [0-9]{9}, was Folgendes ergibt:

awk '{
         while ($0 ~ /[0-9]+\.[0-9]{9}[^ ]/) {
             $0=gensub(/([0-9]+\.[0-9]{9})([^ ])/, "\\1 \\2", $0)
        }
        print
      }' input.txt > first_step.txt

(Irgendwie leichter zu lesen, oder?) Damit sieht es dann first_step.txtso aus:

0.001000000 *********************************************
0.061059059 -3524.927327218 -3524.938421865 ***************
0.121118118 -887.564833130 -887.569649256 -6250.350946527
0.181177177 -387.169559377 -387.173137963 -2743.981985633
0.241236236 -223.812193853 -223.815321341 -1504.799155086
0.301295295 -134.073058536 -134.075910507 -924.916305653
0.361354354  -76.668692929  -76.671412688 -612.480371134

Ersetzen von '*' durch Werte aus den folgenden Zeilen

Dies ist auch etwas schwierig zu erreichen. Angenommen, diese '*'-Zeilen kommen nur am Anfang Ihrer Datei vor. Wir werden zunächst dafür sorgen, dass jede Zeile 4 Felder hat:

awk '/\*/ {
              a=""
              for (i=1; i < 5; i++) {
                  if (i < NF) a=a" "$i
                  else a=a" ***************"
              }
              print a; next
           }
           {print}' first_step.txt > second_step.txt

Ausgabe insecond_step.txt

 0.001000000 *************** *************** ***************
 0.061059059 -3524.927327218 -3524.938421865 ***************
0.121118118 -887.564833130 -887.569649256 -6250.350946527
0.181177177 -387.169559377 -387.173137963 -2743.981985633
0.241236236 -223.812193853 -223.815321341 -1504.799155086
0.301295295 -134.073058536 -134.075910507 -924.916305653
0.361354354  -76.668692929  -76.671412688 -612.480371134

Nun zum spaßigen Teil ...

awk 'BEGIN{first_lines=0}
     /\*/ {for (i=1; i<NF+1;i++) a[NR, i]=$i; next}
     first_lines != 1 {for (i=1; i<NF+1;i++) {a[NR, i]=$i};
                       for (i=NR-1; i > 0; i--) {
                           for (j=1; j < NF +1; j++) {
                               if (a[i, j] ~ /^\**$/) a[i, j] = a[i+1, j]
                           }
                       }
                       for (i=1; i < NR+1; i++) {
                           for (j=1; j < NF +1; j++) {
                               printf("%16s", a[i, j])
                           }
                           printf("\n")
                       }
                       first_lines = 1
                       next
                      }
                      {for (i=1;i<NF+1; i++) printf("%16s", $i)
                       printf("\n")
                      }' second_step.txt > output.txt

Ausgabe:

     0.001000000 -3524.927327218 -3524.938421865 -6250.350946527
     0.061059059 -3524.927327218 -3524.938421865 -6250.350946527
     0.121118118  -887.564833130  -887.569649256 -6250.350946527
     0.181177177  -387.169559377  -387.173137963 -2743.981985633
     0.241236236  -223.812193853  -223.815321341 -1504.799155086
     0.301295295  -134.073058536  -134.075910507  -924.916305653
     0.361354354   -76.668692929   -76.671412688  -612.480371134

verwandte Informationen