Kopieren Sie die vorherige Zeile aus der Textdatei in die aktuelle Zeile


7

Ich habe eine Datei mit Zeilen, genau wie folgt:

A
B
C

Ich möchte eine doppelte Datei in Bash erstellen, die jede Zeile enthält, die mit der Kopie der nächsten Zeile zusammengeführt wird, wie:

A;B
B;C
C;

2
Enthält Ihre Eingabedatei ;Zeichen?
JigglyNaga

Nein, es gibt kein; in der Eingabedatei.
Banuj

Antworten:


18

Verwenden von awk:

awk 'prev{ print prev ";" $0 }
     { prev = $0 }
     END { if (NR) print prev ";" }'

was mit Ihrer Eingabe gibt

A;B
B;C
C;

16

Schneller Weg (beinhaltet das zweimalige Lesen der Datei):

$ tail -n+2 file | paste -d';' file -
A;B
B;C
C;

1
Die Datei wird zweimal gelesen, aber jeder Block wird pastekurz darauf gelesen, tailsodass er sich im Cache befindet. Die Chancen stehen gut, dass es effizienter ist als sed/ awkbasierte Lösungen. Ein Nachteil ist, dass es nicht an Rohren funktionieren kann.
Stéphane Chazelas

1
alternativpaste -d';' file <(sed 1d file)
αғsнιη

8
$ sed 'x;G;s_\n_;_;1d;${p;x;s_$_;_;}' file
A;B
B;C
C;

Was dieser sedAusdruck tut:

  • x: Speichern Sie die eingehende Zeile im Haltebereich und rufen Sie die vorherige ab
  • G: Hänge die neue Zeile (aus dem Haltebereich) an die alte an
  • s_\n_;_: Zeilenumbruch durch a ersetzen ;.
  • 1d: Wenn dies die erste Zeile ist, löschen Sie sie (drucken Sie sie nicht aus) und fahren Sie mit der nächsten fort
  • ${...;}: wenn dies die letzte Zeile ist ...
  • p: Drucken Sie zuerst das verbundene Paar
  • x: die letzte Zeile abrufen
  • s_$_;_: final anhängen ;

6

Etwas einfachere sedLösung ohne Speicherplatz:

sed '$!N;y/\n/;/;p;y/;/\n/;D' file
  • $!Num der nächsten Zeile beizutreten (falls vorhanden; $!wird bei GNU nicht benötigt, sedwenn nicht im POSIX-Modus)
  • y/\n/;/ Ersetzen Sie die Newline durch ;
  • pDrucken Sie die resultierende Linie
  • y/;/\n/ zurück zu newline wechseln, also mit
  • D Sie können die erste Zeile entfernen und mit der nächsten fortfahren

Diese letzte Zeile steht Cnicht C;im Beispiel des OP.
Stéphane Chazelas

Ah, ich dachte, es gäbe eine leere letzte Zeile, aber das ist anscheinend nur ein visueller Effekt der SE-Formatierung. Wir brauchen also, $!y/;/\n/wenn das Trailing ;erforderlich ist.
Philippos

5

Gleiche Grundidee wie die von Torin gegebene awk-Lösung :

$ perl -lne 'print "$last;$_" if defined $last; $last=$_;END{print "$last;" if $.}' file 
A;B
B;C
C;

Oder wenn Sie sich für die ganze Kürze interessieren:

$ perl -lne'$.>1?print"$l;$_":1;$l=$_}{print"$l;"if$.' file 
A;B
B;C
C;

5

Eine Vim-Lösung

Man kann diesen Befehl ausgeben (Dank an Conspicuous Compiler, der dies vorgeschlagen hat):

vim "+%s/\n\(.\+\)*/;\1\n\1" sample.txt

Alternativ und wahrscheinlich üblicher starten Sie Vim, öffnen Sie die Datei und geben Sie den Befehl ex ein:

:%s/\n\(.\+\)*/;\1\n\1

Erläuterung:

Ersetzen Sie das Muster:

  • das neue Zeilenzeichen,\n
  • eine Zeichengruppe \(.+\), die die gesamte nächste Zeile zusammensetzt. Der folgende Quantifizierer *zeigt nur an, dass es null oder mehr Übereinstimmungen geben kann

mit den folgenden:

  • ein Semikolon
  • gefolgt von einem Verweis auf die Zeichengruppe, \1
  • gefolgt vom neuen Zeilenzeichen, \n
  • gefolgt von einem zweiten Verweis auf die Zeichengruppe , \1.

Vor:
Geben Sie hier die Bildbeschreibung ein

Nach:

Geben Sie hier die Bildbeschreibung ein


Für manche kann es hilfreich sein, wenn dies ein Einzeiler ist. zBvim '+*ThisReallylongCommand*'
Auffälliger Compiler

1
Sie vermissen ein + im Einzeiler
D. Ben Knoble

Oau ... so eine schöne Lösung für vim.
Banuj

@ D. Ben Knoble - Ich habe die Provision mit, + behoben. Vielen Dank
Patrick Bacon

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.