저는 초보자 Unix 사용자입니다. 2개의 열이 있는 파일을 행 형식 데이터 파일로 변환하려고 합니다.
샘플 데이터 파일: HEADER 개수: 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
내 쪽에서 필요한 것이 있으면 알려주세요. 저는 유닉스, 64비트 인텔 코어 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
쉘 스크립트에서 위의 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