2열 데이터 파일을 행 형식으로 변환

2열 데이터 파일을 행 형식으로 변환

저는 2열 파일을 행 형식 데이터 파일로 변환하려는 초보자 Unix 사용자입니다.

샘플 데이터 파일: 헤더 수: 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 = "Date", 기록의 필드가 "Date"이고 "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 

관련 정보