Wie füge ich Zeilen mit festem Intervall in einer Datei zusammen?

Wie füge ich Zeilen mit festem Intervall in einer Datei zusammen?

Ich habe eine Datei und ihr Inhalt sieht folgendermaßen aus:

a1
b1
c1
aa
bb
cc
aaa
bbb
ccc
d1
e1
f1
dd
ee
ff
ddd
eee
fff
g1
h1
i1
gg
hh
ii
ggg
hhh
iii

Was ist die beste Möglichkeit, die Zeilen mit festem Intervall (in diesem Fall 3) zusammenzuführen und etwa Folgendes zu erhalten:

a1 aa aaa
b1 bb bbb
c1 cc ccc
d1 dd ddd
e1 ee eee
f1 ff fff
g1 gg ggg
h1 hh hhh
i1 ii iii

Der Algorithmus, um aus der Eingabe die Ausgabe zu erhalten, lautet:

  • Zuerst holen wir uns Zeile 1, also a1.
  • Wir wissen, dass das Intervall 3 ist
  • Also sollten Zeile 1, Zeile (1+3), Zeile (1+3+3) in der gleichen Zeile liegen
  • Ebenso sollten die Zeilen 2, 5, 8 usw. in derselben Zeile liegen.

Diesea1,einUndaaausw. sind nur zufälliger Blindtext und könnten jede beliebige Zeichenfolge sein. Der Punkt ist, dass es ein festes Intervall zwischena1,einUndaaa.

Derzeit verwende ich für diese Aufgabe das Emacs-Tastaturmakro. Ich möchte jedoch wissen, ob es bessere Möglichkeiten gibt, dieses Problem zu lösen. Vielen Dank im Voraus.

Antwort1

Wenn Sie auf gnu/anything sind und die Anzahl der Zeilen ein Vielfaches von 9 ist, können Sie ausführen

split -l9 --filter='pr -3 -s" " -t' infile

Dadurch wird die Eingabe in Abschnitte von neun Zeilen aufgeteilt und jeder Abschnitt wird an den Abschnitt weitergeleitet, pr -3 -s" " -t'der ihn in Spalten aufteilt. Abhängig von der Anzahl der Zeilen und ihrer Länge müssen Sie möglicherweise mit prOptionen -wund experimentieren -l. manWeitere Einzelheiten finden Sie auf der Seite.

Antwort2

Hier ist eine vereinfachte Lösung in awk, die fest codiert ist, um drei Sätze im Abstand von drei Zeilen einzubinden:

{
  if (NR > 1 && (NR % 9) == 0) {
    print a "\n" b "\n" c " " $0
    a=""
    b=""
    c=""
  } else if (NR % 3 == 1) {
    if (NR % 9 > 1) {
      a=a" "$0
    } else {
      a=$0
    }
  } else if (NR % 3 == 2) {
    if (NR % 9 > 2) {
      b=b" "$0
    } else {
      b=$0
    }
  } else {
    if (NR % 9 > 3) {
      c=c" "$0
    } else {
      c=$0
    }
  }
}

Speichern Sie das in einer Datei und führen Sie es aus awk -f thatfile < input. Ich bin sicher, dass es intelligentere Möglichkeiten gibt, dies zu tun, aber ich arbeite nicht jeden Tag mit awk.

Antwort3

Das ist ein bisschen knifflig. Ich kenne kein einziges Dienstprogramm, das das kann:

Diese Pipeline liest (im Wesentlichen) 9 Zeilen gleichzeitig und prformatiert sie in 3 Spalten:

# there are 9 single hyphens below
paste -d: -- - - - - - - - - - < file | while read line; do
    tr : '\n' <<<"$line" | pr -s" " -T -3
done
a1 aa aaa
b1 bb bbb
c1 cc ccc
d1 dd ddd
e1 ee eee
f1 ff fff
g1 gg ggg
h1 hh hhh
i1 ii iii

Dies setzt voraus, dass Ihr eigentlicher Text keinen Doppelpunkt enthält.

Antwort4

Eine sehr einfache und klare Möglichkeit,TXR:

@(repeat)
@x0
@x1
@x2
@y0
@y1
@y2
@z0
@z1
@z2
@  (output)
@x0 @y0 @z0
@x1 @y1 @z1
@x2 @y2 @z2
@  (end)
@(end)

Laufen:

$ txr reshape.txr data
a1 aa aaa
b1 bb bbb
c1 cc ccc
d1 dd ddd
e1 ee eee
f1 ff fff
g1 gg ggg
h1 hh hhh
i1 ii iii

Es gibt Möglichkeiten, dies zusammenzufassen, aber Sie müssen sich etwas mehr anstrengen, um sie zu verstehen, wie zum Beispiel:

@(repeat)
@  (collect :times 9)
@line
@  (end)
@  (bind (x y z) @(tuples 3 line))
@  (output)
@    (repeat)
@x @y @z
@    (end)
@  (end)
@(end)

Hier außerdem, wie jemand, der einigermaßen weiß, was er in Awk tut, es implementieren könnte:

        { a[(NR-1)%9] = $0 }
!(NR%9) { print a[0], a[3], a[6]
          print a[1], a[4], a[7]
          print a[2], a[5], a[8] }

Ausgabe:

$ awk -f reshape.awk data
a1 aa aaa
[ ... ]
i1 ii iii

Und wenn dieser Programmierer wiederholte printMuster abstoßend findet:

        { a[(NR-1)%9] = $0 }
!(NR%9) { for (i = 0; i < 3; i++)
            print a[i], a[i+3], a[i+6] }

TXR Lisp-Lösung:

[(opip (tuples 3) (tuples 3) (mappend transpose)
       (mapcar (aret `@1 @2 @3`)) tprint)
 (get-lines)]

Laufen:

$ txr reshape.tl < data

Auf der Kommandozeile: verwenden Sie -t, lassen Sie das tprint: weg.

$ txr -t '[(opip (tuples 3) (tuples 3) (mappend transpose)
                 (mapcar (aret `@1 @2 @3`)))
           (get-lines)]' < data

Dies funktioniert, indem die Eingabe durch eine Pipeline geleitet wird, die sie in Tripel und dann in Tripel dieser Tripel (im Grunde 3x3-Matrizen aus verschachtelten Listen) unterteilt. Diese Matrizen werden einzeln transponiert und ihre Zeilen werden dann aneinandergereiht, um eine riesige Liste von Tripel zu erstellen. Diese Tripel werden mit dem aretPartial Application Operator, einer String-Interpolation, in Strings umgewandelt und ausgegeben, tprintwobei Listen von Strings als auszugebende Zeilen behandelt werden. Die Syntax

(aret `@1 @2 @3`)

dehnt sich aus zu etwas, das ähnelt

(lambda (. args)
  (apply (lambda (arg1 arg2 arg3)
           `@arg1 @arg2 @arg3`)
         args))

Im Grunde wird implizit eine anonyme Funktion mit einem Argument erstellt, die ihr Argument als eine Liste von Argumenten behandelt, die auf eine anonyme Funktion mit drei Argumenten angewendet werden, wobei @1und @2die @3Argumente bezeichnen. Der Hauptteil der Funktion wird aus dem ursprünglichen Quasi-String-Ausdruck abgeleitet, indem diese speziellen numerischen Parameter durch maschinengenerierte Argumentnamen ersetzt werden.

verwandte Informationen