Wie drucke ich die erste Spalte der nächsten Zeile in der aktuellen Zeile?

8

Ich habe eine Datei wie diese:

abc 123    
abc 789  
bcd 456  
acb 135

Ich möchte die erste Spalte der nächsten Zeile in der aktuellen Zeile drucken.

Gewünschte Ausgabe:

abc  123 abc  
abc 789 bcd  
bcd 456 acb  
acb 135 

Ich benutze lieber awk.

user2905046
quelle

Antworten:

16

Merken Sie sich die vorherige Zeile:

awk 'NR > 1 { print prev, $1 } { prev = $0 } END { print prev }'

Dies verarbeitet die Eingabe wie folgt:

  • Wenn die aktuelle Zeile die zweite oder größere ist, drucken Sie die vorherige Zeile (gespeichert in prev, siehe nächster Schritt) und das erste Feld der aktuellen Zeile, getrennt durch das Ausgabefeldtrennzeichen (standardmäßig das Leerzeichen).
  • Speichern Sie in jedem Fall die aktuelle Zeile in der prevVariablen.
  • Drucken Sie am Ende der Datei die vorherige Zeile.
Stephen Kitt
quelle
11

Alternativer awkAnsatz:

$ awk 'NR == 1{printf "%s", $0;next}{printf " %s\n%s", $1,$0}' input.txt                                    
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135

Die Funktionsweise ist einfach: Die erste Zeile ist ein Sonderfall - wir drucken sie ohne neue Zeile und weisen awk an, zur nächsten Zeile zu wechseln, ohne andere Codeblöcke auszuführen. Danach NR == 1{printf "%s", $0;next}wird übersprungen, aber andere Teile erledigen den Job.

Denken Sie daran, dass wir bisher eine formatierte Zeichenfolge ohne neues Zeilenzeichen gedruckt haben. Was jetzt getan wird, printf " %s\n%s",$1,$0ist, dass das erste Wort ausgedruckt wird (und da es keine neue Zeile gab, bleibt es in derselben Ausgabezeile), die neue Zeile eingefügt und dann die ganze Zeile selbst (aber nicht mit dem Zeilenumbruchzeichen endet). . Somit bleibt das nächste zuerst eingefügte Wort in derselben Zeile. Der Prozess geht weiter und weiter, bis wir das Ende der Datei erreichen.

Mögliche Verbesserung besteht darin, einen END{print ""}Block einzuschließen, um die letzte neue Zeile einzufügen. In bestimmten Fällen, in denen die resultierende Datei von anderen Skripten verarbeitet werden soll, kann dies wünschenswert sein.


Während der Benutzer AWK speziell angefordert hat, kann der gleiche Ansatz beim Drucken formatierter Zeichenfolgen mit anderen Sprachen, beispielsweise Python, verfolgt werden. Python-Alternative für diejenigen, die neugierig sind, wie dies in anderen Sprachen implementiert werden kann:

#!/usr/bin/env python
from __future__ import print_function
import sys

old = None
for index,line in enumerate(sys.stdin):
    if index == 0:
        print(line.strip(),end=" ")
        continue
    words = line.strip().split()
    print(words[0] + "\n" + line.strip(),end=" ")

Und Verwendung wie folgt:

$ ./append_first.py < input.txt                            
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135

Die gleiche Vorstellung von der endgültigen Newline gilt hier.

Sergiy Kolodyazhnyy
quelle
9

Hier ist ein hässlicher sedWeg nur zum Spaß

sed '2,$ s/[^ ]\+/& &/; 2,$ s/ /\n/' file | paste -d ' ' - -
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135 

Erläuterung

  • 2,$ von der zweiten bis zur letzten Zeile
  • s/[^ ]\+/& &/ Verdoppeln Sie den ersten Satz von Nicht-Leerzeichen
  • ; trennt Befehle wie in der Shell
  • s/ /\n/ Ersetzen Sie das erste Leerzeichen durch eine neue Zeile
  • paste -d ' ' - - kleben Sie dieses Durcheinander zusammen (fügen Sie die zweite Zeile der dritten, die vierte Zeile der dritten usw. hinzu)
Zanna
quelle
1
Alternativ können Sie allein verwenden, sedohne paste:sed -r 'N;s/\n(\w+)/\1&/;P;D' somefile.txt
Digital Trauma
1
Wenn Sie schreiben sedProgramme für Spaß, dann sollten Sie vielleicht gehen an haben Code-Golf ;-)
Digital - Trauma
1
@ DigitalTrauma sie ist schon seit 2 Monaten auf Code-Golf;)
Sergiy Kolodyazhnyy
1

Meiner Meinung nach ist der einfachste und am besten lesbare Ansatz:

  1. extrahiere die erste Spalte ( cut)
  2. lösche die erste Zeile aus deiner extrahierten Spalte ( tail)
  3. füge diese Spalte in deine Quelldatei ein ( paste)

Beispiel: Ihre Beispiel-Inpult-Datei:

abc 123    
abc 789  
bcd 456  
acb 135

Führen Sie dann den folgenden Befehl in einem Terminal aus

cut -d' ' -f1 in.txt | tail -n +2 | paste -d' ' file -

Ausgabe:

abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135

Die Struktur hinter dieser Lösung unterscheidet sich von den gegebenen Antworten. Keine Notwendigkeit von Bedingungen, Schleifen oder regulären Ausdrücken.

Hölderlin
quelle