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

awk 手册参考文献说:

对不存在字段(即 $NF 之后的字段)的引用返回空字符串。然而,分配给一个不存在的字段(例如,$(NF+2) = 5)会增加 NF 的值,产生任何干扰 包含空字符串的字段作为它们的值,并导致值$0 需重新计算,字段由 OFS 的值分隔。

你的$(f["Request6"])评估为$0asf["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

相关内容