1

Need support on below

Here is my input file

cat sortcol
InfoId Time object Request1 Request2 Request3 Request4 Request5

I am using below awk script to print column of my choice

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

This scrpt is working fine only how to put condition that if any column requested in this awk script not present in input file than that column should be ignored. As in below examples since loop is running and if it found any unmatched column name its run again and printed all columns from input file.

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

Thanks in advance for all support.

  • How about instead of calling print directly, call a function with the name of the field. The function checks the name is in f, and if so prints out the field and a space (OFS), finally print a newline (ORS). – icarus May 18 at 15:27
-2
$ 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
| improve this answer | |
  • 1
    Dear Ed Morton, Yes, I do agree and accept your answer. Thanks a lot for your support. And Sorry for delayed response – iconluv May 23 at 16:22
0

As already noted, the $(f["field-name"]) expressions in your code translate into $0 (thus expanding to the content of the whole line) whenever f["field-name"] evaluates to the null string—i.e. when field-name doesn't exist in the first row of the input file.

Here is an alternative AWK approach:

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 )
}

Assuming you saved it as script, invoke it as:

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

The list of to-print column names is passed to awk as a variable to let you change it without the need for editing the script.

The main idea is: on the first row, create an array of to-print field numbers (toprint) based on the intersection between the headers from that row and an array (wanted) obtained by splitting the list variable.
Then, for each line, print the fields whose numbers are in the to-print array.

Note that nothing is printed if the script is passed an empty list or if the list includes none of the values from the first row of the input file.

| improve this answer | |
0

Awk Manual Reference says :

References to nonexistent fields (i.e., fields after $NF) return the null-string. However, assigning to a nonexistent field (e.g., $(NF+2) = 5) increases the value of NF, creates any intervening fields with the null string as their value, and causes the value of $0 to be recomputed, with the fields being separated by the value of OFS.

Your $(f["Request6"]) evaluates as $0 as f["Request6"] returns null-string.

You can define the required column list in an array and use like below if it works for you :

$ 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

Test Output :

$ 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
| improve this answer | |
  • Code optimization: Take the print "" out of the for-loop and skip the if-condition for it - it thus will be executed anyway after each for-loop ran. – Fiximan May 19 at 12:04
  • @Fiximan : first printf used to avoid new line , next print after if condition to print new line only at the end of the column list... – Stalin Vignesh Kumar May 19 at 12:12
  • Yes, but for (i=..) { printf " " .. ; if (i=n) print ""} is less effective than for (i=..) {printf " "... } ; print "" -> you skip an if-test for each i in each line! – Fiximan May 19 at 12:14
  • Yes make sense...thanks.. – Stalin Vignesh Kumar May 19 at 12:21
0

If you want the possibility of printing any field, in any order, ignoring (no output) non-existent fields, you can use:

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

Which will print:

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

For an input file of:

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

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.