
Ich versuche, die Zeilenreihenfolge in einem bestimmten Muster zu ändern. Ich arbeite mit einer Datei mit vielen Zeilen (z. B. 99 Zeilen). Bei jeweils drei Zeilen soll die zweite Zeile die dritte Zeile sein und die dritte die zweite Zeile.
BEISPIEL.
1- Eingabe:
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.
...
2- Ausgabe:
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.
...
Antwort1
$ seq 9 | sed -n 'p;n;h;n;G;p'
1
3
2
4
6
5
7
9
8
Das heißt, p
drucken Sie die aktuelle Zeile, holen Sie sich die n
nächste, h
kopieren Sie sie, holen Sie sich die n
nächste, G
kopieren Sie die gehaltene Zeile (hängen Sie sie an den Musterbereich an) und p
drucken Sie diesen 2-zeiligen Musterbereich, wobei die dritte und die zweite Zeile vertauscht sind.
Antwort2
Verwenden awk
von Ganzzahlmathematik:
awk 'NR%3 == 1 { print } NR%3 == 2 { delay=$0 } NR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay } }' /path/to/input
Der Modulo-Operator führt eine Ganzzahldivision durch und gibt den Rest zurück. Daher wird für jede Zeile die Folge 1, 2, 0, 1, 2, 0 [...] zurückgegeben. Da wir das wissen, speichern wir die Eingabe in den Zeilen, in denen der Modulo 2 ist, einfach für später – nämlich direkt nach dem Drucken der Eingabe, wenn sie Null ist.
Antwort3
Verwenden Sie perl
ein kurzes Skript:
user@pc:~$ cat input.txt
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.
user@pc:~$ perl -ne '$l2=<>; $l3=<>; print $_,$l3,$l2;' input.txt
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.
Das Skript verarbeitet die gesamte Datei. Für jede Zeile (gespeichert in $_
) ruft es die nächsten beiden Zeilen ( $l2
und $l3
) ab und druckt sie in der angeforderten Reihenfolge: Zeile1, Zeile3, Zeile2.
Antwort4
Perl
perl -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_ . $var if $.%3==0' input.txt
Die Idee dabei ist, dass wir den Modulo-Operator %
mit Zeilennummernvariablen verwenden $.
, um herauszufinden, welche Zeile die erste, welche die zweite und welche die dritte Zeile ist. Für jede dritte Zeile ist der Rest 0, während es für jede erste und zweite Zeile entsprechende Zahlen gibt.
Prüfen:
$ cat input.txt
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.
$ perl -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_ . $var if $.%3==0' input.txt
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.
Kleine Verbesserung
Der Ansatz, die zweite Zeile in einer Variablen zu speichern, hat einen Fehler. Was ist, wenn die letzte Zeile die „zweite“ ist, d. h. für diese Zeilennummer ist der Rest 2? Der Originalcode in meiner und DopeGhotis Antwort wird nicht gedruckt, My dog is orange
wenn wir die letzte Zeile weglassen. Die Lösung hierfür besteht in beiden Fällen darin, END{}
einen Codeblock zu verwenden und die temporäre Variable nach dem Drucken zurückzusetzen. Mit anderen Worten:
$ awk 'NR%3 == 1 { print } NR%3 == 2 { delay=$0 } NR%3 == 0 { print; print delay;delay=""}END{print delay}' input.txt
Und
$ perl -ne '$s=$_ if $.%3==2;print $_ . $s and $s="" if $.%3==0 or $.%3==1;END{print $s}' input.txt
Auf diese Weise funktioniert der Code für eine beliebige Zeilenzahl in einer Datei und nicht nur für die durch 3 teilbaren.
Zusätzlicher Fix für das in den Kommentaren erwähnte Problem
Wenn im Fall von awk die letzte Zeile in der Datei die Ausgabe 1 für $. % 3 erzeugt, hat der vorherige Code das Problem, dass aufgrund des unbedingten Druckens von ein leeres Newline ausgegeben wird END{print delay}
, da print
die in den Kommentaren erwähnte Funktion immer ein Newline an die Variable anfügt, mit der sie arbeitet. Im Fall von perl
Version tritt dieses Problem nicht auf, da die Funktion mit -ne
Flags print
das Newline nicht anfügt.
Die Lösung im Fall von awk besteht jedoch darin, eine Bedingung zu erstellen, wie Dope Ghoti in den Kommentaren erwähnt, nämlich die Länge der temporären Variable zu überprüfen. Die Perl-Version derselben Lösung wäre:
$ perl -ne '$s=$_ if $.%3==2;print $_ . $s and $s="" if $.%3==0 or $.%3==1;END{print $s if length $s}' input.txt