我是 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
到值數組中field
fields
BEGIN
$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