我是 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