Ändern der Zeilenreihenfolge in einer Datei

Ändern der Zeilenreihenfolge in einer Datei

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, pdrucken Sie die aktuelle Zeile, holen Sie sich die nnächste, hkopieren Sie sie, holen Sie sich die nnächste, Gkopieren Sie die gehaltene Zeile (hängen Sie sie an den Musterbereich an) und pdrucken Sie diesen 2-zeiligen Musterbereich, wobei die dritte und die zweite Zeile vertauscht sind.

Antwort2

Verwenden awkvon 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 perlein 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 ( $l2und $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 orangewenn 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 printdie in den Kommentaren erwähnte Funktion immer ein Newline an die Variable anfügt, mit der sie arbeitet. Im Fall von perlVersion tritt dieses Problem nicht auf, da die Funktion mit -neFlags printdas 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 

verwandte Informationen