將 2 列資料檔轉換為行格式

將 2 列資料檔轉換為行格式

我是 Unix 初學者用戶,嘗試將 2 列的檔案轉換為行格式資料檔案。

範例資料檔:標題計數: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

下面是我嘗試過的程式碼,但我沒有得到所需的輸出。

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

如果我這邊需要什麼,請告訴我。我正在使用 unix、64 位元 intel core i5-5300U CPU、2.30GHz 的 PUTTY。

你能幫我解決這個問題嗎?

問候,納雷什

答案1

由於每個輸入記錄中的欄位數量不一致,因此需要使用 2 遍方法來避免在程式碼中硬編碼列名稱:

$ 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

要在 shell 腳本中使用上述 awk 腳本:

#!/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 ...

答案2

首先,您的程式碼中存在語法錯誤。

區塊中的單引號BEGIN應該是雙引號

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

其次,您不能按照您所做的方式分配變數和列印,這需要修正。

第三,Dn =“日期”,您的記錄中的欄位是“日期”,您對“DOJ”/“JOD”也有同樣的問題

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

這些對BEGIN區塊的更正可以讓您...

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

這是因為邏輯錯誤。

正如 @pLumo 指出的那樣,您的資料集中缺少資料字段,而且您的程式碼不允許這樣做,但更多的awk是在每個記錄(每行)而不是每個記錄集(就在 發生之前empid)進行列印.

有很多方法可以給這隻特殊的貓剝皮,但由於我今天心情很好,這裡有一個簡單的方法可供初學者學習數組...

BEGIN區塊中載入一個包含所需欄位編號的陣列,使用欄位名稱作為索引並列印標題

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"
    }

如果第一個欄位是「empid」且&&它不是第一個記錄NR>1,則迭代將包含您的欄位值的陣列(當NR==1這就是我們跳過它的原因時,該數組為空),並在列印該數組後將其清空重用者delete

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

對於文件中的每一行,根據中的欄位名稱,使用從我們在區塊中建立的數組中恢復的欄位編號作為索引,將值載入$2到值數組中fieldfieldsBEGIN$1

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

當您到達文件末尾時,該數組仍將加載未列印的值,因此您必須最後一次列印該數組

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

編輯

將此腳本複製/貼上到終端中

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

透過這個輸入

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

輸出是

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 

相關內容