Die letzte Zeile der Datei muss in die zweite Zeile derselben Datei verschoben werden

8

Ich habe eine Datei 'Test' unter Linux mit den folgenden Daten.

aaaaaa
bbbbbb
cccccc
dddddd
eeeeee

Ich muss die letzte Zeile dieser Datei ausschneiden und an die zweite Position setzen. Es muss wie folgt aussehen.

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
Vivek William
quelle

Antworten:

9

Dieses Problem ist möglicherweise am einfachsten zu lösen ed, da es sich im Grunde genommen um einen skriptfähigen Texteditor und nicht um einen Stream-Prozessor handelt. Mit edmüssen Sie beispielsweise nicht alle Zeilen der Datei in einem Array speichern, da dies bereits für Sie erledigt wird.

# Create test file
~> printf "%s\n" aaaaaa bbbbbb cccccc dddddd eeeeee >test.txt
~> cat test.txt
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee

# Use ed to open the file, move the last line after the first, save, and quit
~> printf "%s\n" '$m1' wq | ed test.txt
35
35
~> cat test.txt
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
godlygeek
quelle
5

Haltepuffermethode:

sed '$x;1!H;1p;$!d;x;s/\n//
' <<\IN
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee
IN

... das wird Hjede Zeile alt machen, die !nicht die erste ist, und die erste, die sie pdruckt. In der $letzten Zeile werden xdie Halte- und Musterbereiche geändert, bevor die Halte Zeile ausgeführt wird. dDadurch werden die gespeicherten Zeilen an die letzte Zeile angehängt. Anschließend werden alle Zeilen aus der Ausgabe gelöscht, die !nicht die $letzten sind.

In der $letzten Zeile werden xdie Leerzeichen erneut s///geändert, das erste \newline-Zeichen wird ersetzt - das sich um das in Zeile 2 hinzugefügte Zeichen kümmert - und das Los wird dann automatisch gedruckt.

AUSGABE:

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

ohne Verwendung des Haltepuffers:

cat <<\IN >infile
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee
IN

... nur um Ihr Beispiel in einer tatsächlichen Datei zu speichern ...

sed '1p;$!d;r infile' <infile | sed '3d;$d'

Dass Umleitungen <infilezu den ersten sed‚s stdin, die nur pdie erste Zeile Rints vor dvon Ausgangs alle Zeilen eleting, die !nicht die $letzte. Die letzte Zeile ist autoprinted, aber es ist auch die einzige Linie , auf der der letzte Befehl ausgeführt wird -, die ist rdie gesamte ead heraus infile wieder zu stdout. All das wird über das |Rohr zum zweiten geleitet, seddas dann nur noch dseine dritte und letzte Eingangsleitung von seinem Ausgang entfernen muss, um die Neuanordnung abzuschließen.

AUSGABE:

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
mikeserv
quelle
cool, +1. Ich erinnere mich nicht, dass Sie jemals awkLösungen veröffentlicht haben. Sind Sie ein großer sedFan oder haben Sie vielleicht geschrieben sed? ;-)
iruvar
@ 1_CR - Ich weiß nicht, wie man es benutzt awk- ich habe es nie versucht. vielleicht eines Tages ...
mikeserv
2

Ein naiver Ansatz mit awk:

~$ awk '{a[NR]=$0}END{print a[1];print a[NR];for(i=2;i<NR;i++){print a[i]}}' f
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

Sie speichern jede Zeile im aArray und drucken das Array dann in der gewünschten Reihenfolge (1. Zeile, letzte ( NR) und von 2 bis zum vorletzten.

Mit einer Kombination aus Kopf / Schwanz und Sed:

~$ head -1 f;tail -1 f;sed '1d;$d' f
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

Drucken Sie die erste Zeile, die letzte und löschen Sie mit sed die erste und letzte.


Nur mit sed konnte ich diesen Befehl nur finden. Ich bin sicher, es gibt bessere Möglichkeiten:

~$ sed '${p;x;s/^\n//;p};2,${H;d}' f
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

Wenn es die erste Zeile ist, drucken Sie sie aus (Standard).
Legen Sie es in der zweiten Zeile in den Haltepuffer ( H) und löschen Sie es aus dem Musterbereich ( d). Und wenn es die letzte Zeile ist, drucken Sie sie ( p), holen Sie sich den Haltepuffer ( x), löschen Sie die leere Zeile ( s/^\n//) und drucken Sie sie ( p).

Fredtantini
quelle
Mein erster Instinkt wäre, die Kopf / Schwanz-Methode zu verwenden. Eine Alternative zu dem sedTeil wäre so etwas wie head -n -1 f | tail -n +2.
Sparhawk
@Sparhawk die -1Syntax für headdort ist nicht portabel.
Mikeserv
1

Mit Perl:

perl -e 'my @lines = <>; print for @lines[0, $#lines, 1..$#lines-1]' file

Mit awk:

$ awk '
    {lines[NR]=$0}
    END{
        print lines[1], lines[NR];
        for (i=2; i<NR; i++) {print lines[i]}
    }
' OFS=$'\n' file

AUSGABE

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
Gilles Quenot
quelle