Print sorted output with awk to avoid pipe sort command

Viewed 174

I'm trying to match the lines containing (123) and then manipulate field 2 replacing x and + by space that will give 4 columns. Then change order of column 3 by Column 4. To finally print sorted first by column 3 and second by column 4.

I'm able to get the output piping sort command after awk output in this way.

$ echo "
0:   1920x1663+0+0     kpwr(746)
323: 892x550+71+955    kpwr(746)
211: 891x550+1003+410  kpwr(746)
210: 892x451+71+410    kpwr(746)
415: 891x451+1003+1054 kpwr(746)
1:   894x532+70+330    kpwr(123)
324: 894x532+1001+975  kpwr(123)
2:   894x631+1001+330  kpwr(123)
212: 894x631+70+876    kpwr(123)
61:  892x1+71+375      kpwr(0)
252: 892x1+71+921      kpwr(0)" | 
awk '/\(123\)/{b = gensub(/(.+)x(.+)\+(.+)\+(.+)/, "\\1 \\2 \\4 \\3", "g", $2); print b}' |  
sort -k3 -k4 -n

894 532 330 70
894 631 330 1001
894 631 876 70
894 532 975 1001

How can I get the same output using only awk without the need to pipe sort? Thanks for any help.

3 Answers

Here is how you can get it from awk (gnu) itself:

awk '/\(123\)/{
   $2 = gensub(/(.+)x(.+)\+(.+)\+(.+)/, "\\1 \\2 \\4 \\3", "g", $2)
   split($2, a)           # split by space and store into array a
   # store array by index 3 and 4
   rec[a[3]][a[4]] = (rec[a[3]][a[4]] == "" ? "" : rec[a[3]][a[4]] ORS) $2
}
END { 
   PROCINFO["sorted_in"]="@ind_num_asc" # sort by numeric key ascending
   for (i in rec)         # print stored array rec
      for (j in rec[i])
         print rec[i][j]
}' file
894 532 330 70
894 631 330 1001
894 631 876 70
894 532 975 1001

Can you handle GNU awk?:

$ gawk '
BEGIN {
    PROCINFO["sorted_in"]="@val_num_asc"              # for order strategy
}
/\(123\)$/ {                                          # pick records
    split($2,t,/[+x]/)                                # split 2nd field
    if((t[4] in a) && (t[3] in a[t[4]])) {            # if index collision
        n=split(a[t[4]][t[3]],u,ORS)                  # split stacked element
        u[n+1]=t[1] OFS t[2] OFS t[4] OFS t[3]        # add new data
        delete a[t[4]][t[3]]                          # del before rebuilding
        for(i in u)                                   # sort on whole record
            a[t[4]][t[3]]=a[t[4]][t[3]] ORS u[i]      # restack to element
    } else
        a[t[4]][t[3]]=t[1] OFS t[2] OFS t[4] OFS t[3] # no collision, just add
}
END {
    PROCINFO["sorted_in"]="@ind_num_asc"              # strategy on output

    for(i in a)           
        for(j in a[i])
            print a[i][j]
}' file

Output:

894 532 330 70
894 631 330 1001
894 631 876 70
894 532 975 1001

With collisioning data like:

1:   894x532+70+330    kpwr(123)  # this 
1:   123x456+70+330    kpwr(123)  # and this, notice order
324: 894x532+1001+975  kpwr(123)
2:   894x631+1001+330  kpwr(123)
212: 894x631+70+876    kpwr(123)

output would be:

123 456 330 70                    # ordered by the whole record when collision
894 532 330 70
894 631 330 1001
894 631 876 70
894 532 975 1001

I was almost done with writing and my solution was ditto as @anubhava's so adding a bit tweak to his solution :) This one will take care of multiple lines of same values here.

awk '
BEGIN{
  PROCINFO["sorted_in"]="@ind_num_asc"
}
/\(123\)/{
   $2 = gensub(/(.+)x(.+)\+(.+)\+(.+)/, "\\1 \\2 \\4 \\3", "g", $2)
   split($2, a," ")
   arr[a[3]][a[4]] = (arr[a[3]][a[4]]!=""?arr[a[3]][a[4]] ORS:"")$2
}
END { 
   for (i in arr){
      for (j in arr[i]){ print arr[i][j] }
   }
}' Input_file
Related