2017-08-31 2 views
0

Lassen Sie uns sagen, wir haben zwei Dateien (gleiche Größe m * n-Matrizen), mit Säulen:Wie verschachtelt man Spalten aus zwei Dateien?

A1, A2, A3, A4, ..., An 

und

B1, B2, B3, B4, ..., Bn 

Die erwartete Ausgabe wäre:

A1, B1, A2, B2, A3, B3, A4, B4, ..., An, Bn 

Wie kann das getan werden? Ich nehme an, dass es einige awk-Einzeiler gibt, aber ich konnte den richtigen nicht bauen ...

+0

Was haben Sie versucht? Die meisten von uns hier sind glücklich, Ihnen zu helfen, Ihr Handwerk zu verbessern, aber sind weniger glücklich, als kurze Bestellung unbezahlte Programmierer zu handeln. Zeigen Sie uns Ihre bisherige Arbeit in einem [MCVE] (http://stackoverflow.com/help/mcve), dem Ergebnis, das Sie erwartet haben, und den Ergebnissen, die Sie erhalten haben, und wir werden Ihnen helfen, es herauszufinden. – ghoti

Antwort

1

So etwas scheint in meinen Tests in Ordnung zu sein, wenn man bedenkt, dass beide Dateien die gleiche Anzahl an Zeilen und Felder = Array gleiche Abmessungen:

$ cat file1 
a1,a2,a3 
a4,a5,a6 

$ cat file2 
b1,b2,b3 
b4,b5,b6 

$ awk 'NR==FNR{f1[FNR]=$0;next};{split(f1[FNR],ff1,",");split($0,ff2,","); \ 
for (f=1;f<=length(ff1);f++) printf ff1[f]","ff2[f](f!=length(ff1)?",":"\n")}' file1 file2 
a1,b1,a2,b2,a3,b3 
a4,b4,a5,b5,a6,b6 

Kurze Erklärung:
awk liest zuerst die eine Datei und die zweite Datei.
NR==FNR{f1[FNR]=$0;next}: Lesen Sie die erste Datei und erstellen Sie ein Array f1 mit Indices die Zeilennummer von file1 und Inhalt der ganze Zeile 0 $

Wenn die erste Datei dann fertig ist der Rest des Codes während der Verarbeitung von file2 ausgeführt:

split(f1[FNR],ff1,","): Da beide Dateien die gleiche Anzahl von Zeilen haben, spaltet diese vorherige gelesene Datensätze von Datei1 (gespeichert in Array f1) in ein neues Array ff1, indem Sie Komma als Trennzeichen verwenden.

split($0,ff2,","): Gleichermaßen teilt dies $ 0 = aktueller Datensatz/aktuelle Zeile von Datei2 in ein Array mit dem Namen ff2, mit Komma als Trennzeichen.

for (f=1;f<=length(ff1);f++) printf ff1[f]","ff2[f](f!=length(ff1)?",":"\n")
diesem einen iteriert durch den Array-Elementen von FF1 (FF1 die gleiche Länge hat FF2) und druckt Daten aus beiden FF1 und FF2.

(f!=length(ff1)?",":"\n"): Dieses druckt Komma ,, während wir nicht das Ende der Array FF1/FF2 erreicht haben, sonst druckt ein Newline-Zeichen \n

+1

Sowohl diese als auch Ed Mortons Antworten funktionieren einwandfrei (wie in der Frage angegeben, sind die Dateien m * n Matrizen, nicht nur eine Zeile). Diese Antwort wurde aufgrund der detaillierten Erklärung als korrekt markiert. – Elabore

2
awk ' 
    BEGIN { FS=OFS=", " } 
    NR==FNR { a[NR]=$0; next } 
    { 
     split(a[FNR],f) 
     for (i=1;i<=NF;i++) { 
      printf "%s%s%s%s", f[i], OFS, $i, (i<NF?OFS:ORS) 
     } 
    } 
' a.txt b.txt 
0

Wenn, wie Sie Ihre Eingabe schon sagt, sind Sie nur eine einzige mit Zeile jeder Eingabe, dann Verarbeitung nach Datensatz möglicherweise einfacher als die Verarbeitung nach Feld. Sie können eine Datei über stdin lesen und die andere Datei explizit lesen.

Als einzeiler, dies könnte wie folgt aussehen:

awk 'BEGIN {ORS=RS=","} {print $1; getline < "f2"; print $1}' f1; echo 

mit Kommentaren zur besseren Ablesbarkeit ausgebrochenen:

awk ' 
    BEGIN { ORS=RS="," }  # record separator is a comma! 
    { 
    print $1    # print a trimmed (1-field) record from the first file, 
    getline < "file2"  # then get the next record from the second file. 
    print $1    # print a record from the second file. 
    } 
' file1 
echo      # print a newline, since awk didn't. 

Wenn Sie Ihren Ausgang Leerzeichen nach dem Komma haben lieber Sie können den Code in dem BEGIN Block mit ersetzen:

BEGIN {RS=","; ORS=", "} 
0

verwendenund rs (reshape a data array), falls verfügbar. Wenn nicht, sprich mit deinem lokalen Administrator oder hack den Planeten.Zuerst Testdaten:

$ cat foo bar 
a1,a2,a3 
b1,b2,b3 

dass tr senden ersetzen , mit Raum:

$ cat foo bar | tr , ' ' 
a1 a2 a3 
b1 b2 b3 

und auf rs für die Umsetzung:

$ cat foo bar | tr , ' ' | rs -T 
a1 b1 
a2 b2 
a3 b3 

und schließlich an einem anderen rs drücken vorherigen in einer Zeile:

$ cat foo bar | tr , ' ' | rs -T | rs 1 
a1 b1 a2 b2 a3 b3 

Die letzte rs könnte durch tr \n' ' ' ersetzt werden. rs ehrt Begrenzer für die Eingabe und Ausgabe, siehe die man-Seite dafür. Ich habe die Kommas bewusst verlassen.

0

Paste + tr + Sed Trick für Unix-Shell:

file1 Inhalt:


file2 Inhalt:

B1, B2, B3, B4, B5, B6, B7 

paste <(tr ',' '\n' <file1) <(tr ',' '\n' <file2) | paste -s | sed 's/[[:space:]]\+/, /g' 

Der Ausgang:

A1, B1, A2, B2, A3, B3, A4, B4, A5, B5, A6, B6, A7, B7 
+1

Wichtig zu betonen, dass diese Lösung von 'bash' für die Prozesssubstitution abhängt. Das OP hat nicht angegeben, welche Shell oder welches Betriebssystem sie verwenden. – ghoti

+0

@ghoti, hinzugefügt * für Unix-Shell * – RomanPerekhrest

+1

Prozesssubstitution ist kein Teil von Asche, Strich, Csh, Tcsh. Ich glaube, Bashs Notation wird von AT & T ksh geteilt (aber ich denke nicht pdksh), aber dieses Nicht-POSIX-Feature funktioniert anders in zsh und ich weiß nicht, ob es in Fisch unterstützt wird. Was bedeutet "* für Unix Shell *"? – ghoti

Verwandte Themen