Stellen Sie sich eine Ausgabe eines Befehls wie vor
44444
55555
11111
22222
33333
Wie kann ich die ersten N Zeilen (die ersten beiden im obigen Beispiel) ziehen und am Ende anhängen, ohne jedoch eine temporäre Datei zu verwenden (also nur Pipes)?
11111
22222
33333
44444
55555
Etwas in der Art von | sed -n '3,5p;1,2p'
(was offensichtlich nicht funktioniert, da sed sich nicht um die Reihenfolge der Befehle kümmert).
command-line
text-processing
Peter Uhnak
quelle
quelle
Antworten:
Kopieren Sie diese Zeilen einfach in den Haltepuffer (und löschen Sie sie dann) und hängen Sie in der letzten Zeile den Inhalt des Haltepuffers an den Musterbereich an:
Mit
gnu sed
könnte man es schreiben alsHier ist ein anderer Weg mit ol '
ed
(esr
führt die Ausgabe vonsome command
in den Textpuffer und übergibt dannm
Zeilen1,NUMBER
nach dem letzten$
):Beachten Sie, dass - wie bereits erwähnt - beide fehlschlagen, wenn die Ausgabe weniger als
NUMBER
+1 Zeilen enthält. Ein soliderer Ansatz wäre (gnu sed
Syntax):Dieser löscht nur Zeilen in diesem Bereich, solange sie nicht die letzte Zeile sind (
$!d
). Andernfalls wird der Musterbereich mit dem Haltepufferinhalt (g
) überschrieben und dannq
beendet (nach dem Drucken des aktuellen Musterbereichs).quelle
sed -e '1,NUMBER{H;1h;d;}' -e '$G'
funktioniert auch portabel (beachten Sie, dass einigesed
Implementierungen nicht mehr als ein paar Kilobyte im Haltebereich enthalten können , sodass NUMBER dort nicht zu groß sein kann)sed -e '1,NUMBER{H;1h;d' -e'}' -e '$G'
?-e
ersetzt eine neue Zeile eine neue Zeile.d;}
ist noch nicht POSIX, aber portabel. Dies wird in der nächsten POSIX-Spezifikation behoben. Siehe austingroupbugs.net/view.php?id=944#c27201,NUMBER{H;1h;d;}
ist es nicht tragbar, nicht unmittelbar nach der Eröffnungsklammer ein Semikolon zu haben . Das könnte ein Fehler in SunOS 4.1 gewesen sein,sed
dessen Problemumgehung 20 Jahre später immer noch in meinen Fingern steckt.Ein
awk
Ansatz:Ein Vorteil gegenüber dem
sed
Ansatz von @ don_crissti besteht darin, dass es immer noch funktioniert (die Zeilen ausgibt), wenn die Ausgaben
Zeilen oder weniger enthält.quelle
\n
durch ORS ersetzen , damit dies mit anderen Datensatztrennzeichen funktioniert (z. B. wenn Sie Absätze usw. verwenden möchten).Ich habe
xclip
und damit kann dies auf folgende Weise geschehen:Hier ist seine Beschreibung:
quelle
Ein Perl-Weg:
Oder dasselbe weniger kryptisch geschrieben:
Beispielsweise:
Erläuterung
-ne
: Lesen Sie die Eingabedatei / den Stream zeilenweise und wenden Sie das von-e
jeder Zeile angegebene Skript an.$.<3
:$.
ist die aktuelle Zeilennummer. Wechseln Sie also3
zu der Anzahl der Zeilen, die Sie verschieben möchten.$.<3?($f.=$_):print;
: Dies ist der bedingte Operator, das allgemeine Format istcondition ? case1 : case2
, es wird ausgeführt,case1
wenncondition
es wahr ist undcase2
wenn es falsch ist. Wenn hier die aktuelle Zeilennummer kleiner als 3 ist, wird die aktuelle Zeile ($_
) an die Variable angehängt ,$f
und wenn die Zeilennummer größer als 3 ist, wird gedruckt.}{ print $f
: das}{
ist Perl Abkürzung fürEND{}
. Es wird ausgeführt, nachdem alle Eingabezeilen verarbeitet wurden. Zu diesem Zeitpunkt haben wir alle Zeilen gesammelt, die wir verschieben möchten, und alle Zeilen gedruckt, die wir in Ruhe lassen möchten. Drucken Sie also die Zeilen aus, unter denen gespeichert wurde$f
.quelle
perl -ne '$.<3?$f.=$_:print}{print $f
Verwenden Sie POSIX
ex
. Ja, es ist für die Dateibearbeitung vorgesehen, funktioniert jedoch in einer Pipeline.Dies kann beliebige Befehle am Anfang oder Ende der Pipeline hinzufügen und funktioniert genauso. Besser noch, angesichts des Vorhandenseins von
/dev/stdin
ist es POSIX-konform.(Ich weiß nicht, ob
/dev/stdin
in POSIX angegeben ist oder nicht, aber ich sehe, dass es sowohl in Linux als auch in Mac OS X vorhanden ist.)Dies hat einen Vorteil in Bezug auf die Lesbarkeit gegenüber der Verwendung
sed
des Haltebereichs - Sie sagen einfachex
"Verschieben dieser Zeilen bis zum Ende" und dies geschieht. (Die restlichen Befehle bedeuten "Drucken des Puffers" und "Beenden", die ebenfalls gut lesbar sind.)NB: Der
ex
oben angegebene Befehl schlägt fehl, wenn weniger als 2 Zeilen als Eingabe angegeben werden.Weiterführende Literatur:
quelle
Ein kurzer
python
Ausschnitt:Übergeben Sie den Dateinamen als erstes Argument und die Anzahl der Zeilen, die als zweites Argument verschoben werden sollen.
Beispiel:
quelle
Wenn Sie die gesamte Ausgabe im Speicher speichern können:
quelle
Hier ist eine weitere Option, für die GNU erforderlich ist
sed
:-u
macht GNUsed
ungepuffert, so dass dersed
Befehl nicht mehr als 3 Zeilen STDIN verbraucht. Die Befehlssubstitution entfernt leere Zeilen, sodass der Befehl keine leeren Zeilen am Ende der Ausgabe enthält, wenn die dritte, dritte und zweite oder dritte, zweite und erste Zeile leer sind.Sie können auch so etwas tun:
Ohne
sponge /dev/stdout|
den Befehl würde mit langen Eingaben fehlschlagen.sponge /dev/stdout
kann auch ersetzt werden ,tac|tac
obwohl der Druck zum Beispiel, aucha\ncb
wenn der Eingang ,a\nb\nc
wo\n
ein Zeilenvorschub ist, oder mit(x=$(cat);printf %s\\n "$x")
, auch wenn dies entfernt leeren Zeilen ab dem Ende des Eingangs. Der obige Befehl löscht die erste Zeile, wenn die Anzahl der Zeilen der Eingabe eins oder zwei beträgt.quelle