awk는 열 이름을 기반으로 데이터를 인쇄합니다.

awk는 열 이름을 기반으로 데이터를 인쇄합니다.

다음과 같은 지원이 필요합니다

이것은 내 입력 파일입니다.

cat sortcol
InfoId Time object Request1 Request2 Request3 Request4 Request5

다음 awk 스크립트를 사용하여 선택한 열을 인쇄하고 있습니다.

awk '
NR==1 {
for (i=1; i<=NF; i++) {
f[$i] = i
}
}
{ print $(f["InfoId"]), $(f["Time"]), $(f["object"]), $(f["Request1"]) , 
$(f["Request2"]) }
' sortcol | column -t
InfoId  Time  object  Request1  Request2

조건을 설정하는 방법에 따라 스크립트는 잘 작동합니다. 이 awk 스크립트에서 요청한 열이 입력 파일에 없으면 해당 열을 무시해야 합니다. 아래 예와 같이 루프가 실행 중이므로 일치하지 않는 열 이름이 발견되면 다시 실행되고 입력 파일의 모든 열이 인쇄됩니다.

awk '
NR==1 {
for (i=1; i<=NF; i++) {
f[$i] = i
}
}
{ print $(f["InfoId"]), $(f["Time"]), $(f["object"]), $(f["Request1"]) ,$(f["Request2"]) , $(f["Request6"]) }
' sortcol | column -t
InfoId  Time  object  Request1  Request2  InfoId  Time  object  Request1  Request2  Request3  Request4  Request5

모든 지원에 미리 감사드립니다.

답변1

~처럼이미 알아차렸어$(f["field-name"]), 코드의 표현식은 빈 문자열로 평가될 때마다, 즉 입력 파일의 첫 번째 라인에 없을 때 로 변환됩니다 $0(따라서 전체 라인의 내용으로 확장됩니다) .f["field-name"]field-name

또 다른 AWK 접근 방식은 다음과 같습니다.

BEGIN {
  nwanted = split(list,wanted,",")
}
NR == 1 {
  for ( iwanted = 1; iwanted <= nwanted; iwanted ++ )
    for ( ifield = 1; ifield <= NF; ifield++ )
      if ( wanted[iwanted] == $ifield )
        toprint[++ntoprint] = ifield
}
{
  for ( itoprint = 1; itoprint <= ntoprint; itoprint++ )
    printf( "%s%s", $toprint[itoprint], itoprint == ntoprint ? ORS : OFS )
}

다음과 같이 저장한다고 가정합니다 script.

awk -v list="InfoId,Time,object,..." -f script input_data

인쇄할 컬럼 이름은 변수로 list전달되므로 awk스크립트를 편집하지 않고도 변경할 수 있습니다.

주요 아이디어는 첫 번째 줄에서 toprint행 헤더와 변수를 분할하여 얻은 배열( ) 사이의 교차점을 기반으로 인쇄할 필드 번호의 배열( )을 생성하는 것입니다. 그런 다음 각 행에 대해 배열에 번호가 있는 필드를 인쇄합니다.wantedlist
to-print

빈 목록을 스크립트에 전달하거나 목록에 입력 파일의 첫 번째 줄에 있는 값이 포함되어 있지 않으면 아무것도 인쇄되지 않습니다.

답변2

이상한 매뉴얼참조 내용은 다음과 같습니다.

존재하지 않는 필드(즉, $NF 이후의 필드)에 대한 참조는 빈 문자열을 반환합니다. 그러나 존재하지 않는 필드(예: $(NF+2) = 5)에 할당하면 NF 값이 증가하므로 간섭이 발생하지 않습니다. 빈 문자열이 포함된 필드그 가치로 인해 가치가 발생합니다.$0를 다시 계산해야 합니다.필드는 OFS 값으로 구분됩니다.

당신의$(f["Request6"])다음과 같이 평가됨$0as는 f["Request6"]빈 문자열을 반환합니다.

배열에 필요한 열 목록을 정의하고 다음과 같이 사용할 수 있습니다(적절한 경우).

$ awk '
    BEGIN {
        cols = "InfoId,Time,object,Request6,Request7,Request8,Request9,Request1,Request2,Request3,Request4,Request5"
        totcols=split(cols, newf, ",")
    } 
    NR == 1 {
        for (i = 1; i <= NF; i++)  f[$i] = i
        } 

        { 
          for (i = 1; i <=totcols; i++) 
            printf "%s " , f[newf[i]] ? $f[newf[i]] : "" 
          print ""
    } ' test | column -t

테스트 출력:

$ cat test
InfoId Time object Request1 Request2 Request3 Request4 Request5
123  time obj2  req1  req2 req3 req4 req5
123  time obj2  req1  req2 req3 req4 req5
123  time obj2  req1  req2 req3 req4 req5
123  time obj2  req1  req2 req3 req4 req5
123  time obj2  req1  req2 req3 req4 req5
123  time obj2  req1  req2 req3 req4 req5
123  time obj2  req1  req2 req3 req4 req5
123  time obj2  req1  req2 req3 req4 req5
123  time obj2  req1  req2 req3 req4 req5
123  time obj2  req1  req2 req3 req4 req5


 $  awk '
        BEGIN {
            cols = "InfoId,Time,object,Request6,Request7,Request8,Request9,Request1,Request2,Request3,Request4,Request5"
            totcols=split(cols, newf, ",")
        } 
        NR == 1 {
            for (i = 1; i <= NF; i++)  f[$i] = i
            } 

            { 
             for (i = 1; i <=totcols; i++) 
                printf "%s " , f[newf[i]] ? $f[newf[i]] : "" 
             print ""
        } ' test | column -t
    InfoId  Time  object  Request1  Request2  Request3  Request4  Request5
    123     time  obj2    req1      req2      req3      req4      req5
    123     time  obj2    req1      req2      req3      req4      req5
    123     time  obj2    req1      req2      req3      req4      req5
    123     time  obj2    req1      req2      req3      req4      req5
    123     time  obj2    req1      req2      req3      req4      req5
    123     time  obj2    req1      req2      req3      req4      req5
    123     time  obj2    req1      req2      req3      req4      req5
    123     time  obj2    req1      req2      req3      req4      req5
    123     time  obj2    req1      req2      req3      req4      req5
    123     time  obj2    req1      req2      req3      req4      req5

답변3

존재하지 않는 필드를 무시(출력하지 않음)하고 순서에 관계없이 모든 필드를 인쇄하려면 다음을 사용할 수 있습니다.

listOfInputFields="InfoId Request6 Time object TestField Request4 Request66 Request2"

awk -v loif="$listOfInputFields" '
     NR==1 { for (i=1;i<=NF;i++) { names[$i]=i }
             nif=split(loif, tmp)
             for (i=1; i<=nif; i++) if(names[tmp[i]]!="") { out[++outnf]=names[tmp[i]] }
           }
           {
             FieldSep=""
             for (i=1; i<=outnf; i++) {
               printf "%s%s", FieldSep, $(out[i])
               FieldSep=OFS
           }
           printf "%s", ORS
           }' file | column -t

다음을 인쇄합니다:

InfoId Time object Request4 Request2
1:II   2:T  3:o    7:R4     5:R2

입력의 경우 file:

InfoId Time object Request1 Request2 Request3 Request4 Request5
1:II   2:T  3:o    4:R1     5:R2     6:R3     7:R4     8:R5

답변4

$ cat tst.awk
NR==1 {
    for (i=1; i<=NF; i++) {
        name2nr[$i] = i
    }
    split("InfoId Time object TestField Request1 Request2 Request6", tmp)
    for (i=1; i in tmp; i++) {
        name = tmp[i]
        if (name in name2nr) {
            f[++nf] = name2nr[name]
        }
    }
}
{
    for (i=1; i<=nf; i++) {
        printf "%s%s", $(f[i]), (i<nf ? OFS : ORS)
    }
}

$ awk -f tst.awk file
InfoId Time object Request1 Request2

관련 정보