Konvertieren einer 2-spaltigen Datendatei in das Zeilenformat

Konvertieren einer 2-spaltigen Datendatei in das Zeilenformat

ich bin ein Unix-Anfänger und versuche, eine Datei mit zwei Spalten in eine Datendatei im Zeilenformat zu konvertieren.

Beispieldatendatei: HEADER-Anzahl: 6, EMPID, EMPNAME, SALARY, DEPT, AGE, JOD

col1;col2

empid;1001
empname;ABC
salary;3000
dept;ABC
age;24
JOD;20170101
empid;2001
salary;5000
dept;XYZ
age;27
JOD;20170303
empid;1002
empname;MAN
salary;11000
dept;SCI
age;30
JOD;20180607
empid;1005
empname;NAME
salary;10200
dept;XYZ
JOD;20161212

Unten ist der Code, den ich ausprobiert habe, aber ich erhalte nicht die gewünschte Ausgabe.

awk '
BEGIN {FS=';'
       OFS=';'
       RS="\n"
Print An = "empid", Bn = "empname", Cn = "salary", Dn = "Dept", En = "age", Fn = "DOJ"
     }
     {
     A=B=C=D=E=F=" "
     for ( i = 1; i<=NF; i++)
          {
           if($i == An)
                A = $(i+1)
           if($i == Bn)
                B = $(i+1)
           if($i == Cn)
                C = $(i+1)
           if($i == Dn)
                D = $(i+1)
           if($i == En)
                E = $(i+1)
           if($i == Fn)
                F = $(i+1)
             }
            print A, B, C, D, E, F
             }' FILE.txt >New_file.txt

Lassen Sie mich wissen, ob von meiner Seite etwas erforderlich ist. Ich verwende PUTTY für Unix, 64-Bit Intel Core i5-5300U CPU, 2,30 GHz.

Könnten Sie mir dabei bitte weiterhelfen? Das wäre eine große Hilfe.

Grüße, Naresh

Antwort1

Da Sie nicht in jedem Eingabedatensatz über eine konsistente Anzahl von Feldern verfügen, ist ein zweistufiger Ansatz erforderlich, um zu vermeiden, dass Sie Spaltennamen in Ihrem Code fest codieren müssen:

$ cat tst.awk
BEGIN { FS=OFS=";" }
NR==FNR {
    if ( !($1 in colNrs) ) {
        colNrs[$1] = ++numCols
        hdr = (numCols>1 ? hdr OFS : "") $1
    }
    next
}
FNR == 1 { print hdr }
{ colNr = colNrs[$1] }
colNr in vals { prt() }
{ vals[colNr] = $2 }
END { prt() }

function prt(   colNr) {
    for (colNr=1; colNr<=numCols; colNr++) {
        printf "%s%s", vals[colNr], (colNr<numCols ? OFS : ORS)
    }
    delete vals
}

.

$ awk -f tst.awk file file
empid;empname;salary;dept;age;JOD
1001;ABC;3000;ABC;24;20170101
2001;;5000;XYZ;27;20170303
1002;MAN;11000;SCI;30;20180607
1005;NAME;10200;XYZ;;20161212

So verwenden Sie das obige Awk-Skript in einem Shell-Skript:

#!/bin/env bash

... other shell stuff ...

awk '
BEGIN { FS=OFS=";" }
NR==FNR {
    if ( !($1 in colNrs) ) {
        colNrs[$1] = ++numCols
        hdr = (numCols>1 ? hdr OFS : "") $1
    }
    next
}
FNR == 1 { print hdr }
{ colNr = colNrs[$1] }
colNr in vals { prt() }
{ vals[colNr] = $2 }
END { prt() }

function prt(   colNr) {
    for (colNr=1; colNr<=numCols; colNr++) {
        printf "%s%s", vals[colNr], (colNr<numCols ? OFS : ORS)
    }
    delete vals
}
' file file

... other shell stuff ...

Antwort2

Zunächst einmal enthält Ihr Code Syntaxfehler.

Die einfachen Anführungszeichen in Ihrem BEGINBlock sollten doppelt sein

BEGIN {FS=";";
       OFS=";";
       RS="\n";

Zweitens können Sie Variablen nicht auf die Art und Weise zuweisen und drucken, wie Sie es getan haben. Dies muss korrigiert werden.

Drittens: Dn = „Datum“ und das Feld in Ihren Datensätzen ist „Datum“ und Sie haben das gleiche Problem mit „DOJ“/„JOD“.

        An = "empid"; Bn = "empname"; Cn = "salary"; Dn = "dept"; En = "age"; Fn = "JOD";
        print An, Bn, Cn, Dn, En, Fn
     }

Diese Korrekturen am BEGINBlock ermöglichen Ihnen ...

empid;empname;salary;dept;age;JOD
1001; ; ; ; ; 
 ;ABC; ; ; ; 
 ; ;3000; ; ; 
 ; ; ;ABC; ; 
 ; ; ; ;24; 
 ; ; ; ; ;20170101
2001; ; ; ; ; 
 ; ;5000; ; ; 
 ; ; ;XYZ; ; 
 ; ; ; ;27; 
 ; ; ; ; ;20170303
1002; ; ; ; ; 
 ;MAN; ; ; ; 
 ; ;11000; ; ; 
 ; ; ;SCI; ; 
 ; ; ; ;30; 
 ; ; ; ; ;20180607
1005; ; ; ; ; 
 ;NAME; ; ; ; 
 ; ;10200; ; ; 
 ; ; ;XYZ; ; 
 ; ; ; ; ;20161212

Was auf logische Fehler zurückzuführen ist.

Wie @pLumo anmerkt, fehlen in Ihren Datensätzen Datenfelder und Ihr Code lässt dies nicht zu, sondern awkdruckt vielmehr bei jedem Datensatz (jeder Zeile) und nicht bei jedem Datensatzsatz (direkt vor dem Auftreten von empid).

Es gibt viele Möglichkeiten, dieses Problem zu lösen, aber da ich heute gut gelaunt bin, hier eine einfache Methode, mit der Anfänger Arrays lernen können …

Laden Sie im BEGINBlock ein Array mit den gewünschten Feldnummern, wobei Sie die Feldnamen als Indizes verwenden, und drucken Sie die Titel

awk -F";" 'BEGIN{
    fields["empid"]=1;
    fields["empname"]=2;
    fields["salary"]=3;
    fields["dept"]=4;
    fields["age"]=5;
    fields["JOD"]=6;
    print "empid;empname;salary;dept;age;JOD"
    }

Wenn das erste Feld "empid" ist und &&es nicht der erste Datensatz ist, NR>1dann iterieren Sie über das Array, das Ihre Feldwerte enthalten wird (das Array ist leer, wenn NR==1es leer ist, deshalb überspringen wir es) und nachdem Sie das Array gedruckt haben, leeren Sie es zur Wiederverwendung durchdelete

    $1=="empid" && NR>1 {
         for (f=1; f<6; f++) printf field[f]";"; print field[6]; delete field}

Laden Sie für jede Zeile in der Datei den Wert $2in Ihr Werte-Array und fieldverwenden Sie dabei die Feldnummer aus dem fieldsArray, das wir im BEGINBlock erstellt haben, als Index, basierend auf dem Feldnamen in$1

   {field[fields[$1]]=$2

Das Array wird immer noch mit ungedruckten Werten geladen, wenn Sie das Ende der Datei erreichen und Sie müssen das Array ein letztes Mal ausdrucken.

    }END{for (f=1; f<6; f++) printf field[f]";"; print field[6]}' file1

Bearbeiten

Mit diesem Skript in das Terminal kopieren/einfügen

awk -F";" 'BEGIN{
    fields["empid"]=1;
    fields["empname"]=2;
    fields["salary"]=3;
    fields["dept"]=4;
    fields["age"]=5;
    fields["JOD"]=6;
    print "empid;empname;salary;dept;age;JOD"
    }$1=="empid" && NR>1 {
         for (f=1; f<6; f++) printf field[f]";"; print field[6]; delete field}{field[fields[$1]]=$2 
         }END{for (f=1; f<6; f++) printf field[f]";"; print field[6]}' file1

Mit diesem Eingang

empid;1001
empname;ABC
salary;3000
dept;ABC
age;24
JOD;20170101
empid;2001
salary;5000
dept;XYZ
age;27
JOD;20170303
empid;1002
empname;MAN
salary;11000
dept;SCI
age;30
JOD;20180607
empid;1005
empname;NAME
salary;10200
dept;XYZ
JOD;20161212

Ausgabe ist

empid;empname;salary;dept;age;JOD
1001;ABC;3000;ABC;24;20170101
2001;;5000;XYZ;27;20170303
1002;MAN;11000;SCI;30;20180607
1005;NAME;10200;XYZ;;20161212 

verwandte Informationen