Print file in particular order in awk

2019-07-14 20:20发布

I am following this link https://stackoverflow.com/a/54599800/10220825

file.txt

Iteration 1
RAM: +2s
Cache: +142ms (total +417ms)

Iteration 2
RAM: +184ms
Cache: +172ms
Searchms: +131ms (total +385ms)

Iteration 3
RAM: +149ms
Searchms: +3.2s

I want to remove the ms or s from the time value but not from name (example it should not remove Searchms to Search). Also I want to convert s into ms by multiply into 1000 if the time value contains s and print result accordingly.

Expected Output:

RAM: 2000 184 149
Cache: 142 172
Searchms: 131 3200

try.awk

/:/{vals[$1]=vals[$1] OFS $2+0}
END {
         for (key in vals)
          print key vals[key]
}

On executing : awk -f try.awk file.txt

Code Output:

Cache: 142 172
Searchms: 131 3.2
RAM: 2 184 149

In my output s is not converting to ms. Please suggest me how I modify above source code try.awk to convert s to ms.


New Test Case: file.txt

Iteration 1
RAM: +2s342ms

Iteration 2
RAM: +2s

Iteration 3
RAM: +149ms

Code:

/:/ && $2 ~/ms$/{vals[$1]=vals[$1] OFS $2+0;next}
/:/ && $2 ~/[^m]s$/{vals[$1]=vals[$1] OFS ($2+0)*1000}
END {
         for (key in vals)
          print key vals[key]
}

Expected output:

RAM: 2342 2000 149

Output:

RAM: 2 2000 149

标签: shell awk sed
2条回答
\"骚年 ilove
2楼-- · 2019-07-14 20:53

A small adaptation of the OP:

/:/{  vals[$1]=vals[$1] OFS $2*($2~/ms$/ ? 1 : 1000 ) }
END { for (key in vals) print key vals[key] }

Remark: this will not work on all versions of awk, this makes use of the following nifty feature of gawk (and POSIX):

A string is converted to a number by interpreting any numeric prefix of the string as numerals: "2.5" converts to 2.5, "1e3" converts to 1,000, and "25fix" has a numeric value of 25. Strings that can’t be interpreted as valid numbers convert to zero.

source: Gnu Awk manual: Conversion of Strings and Numbers

This behaviour is Posix valid and works using the C-function atof. POSIX, however, gives a second option to convert strings to numbers where "25fix" would convert to 0. This is, for example, the case on Oracle:

Linux: GNU $ awk 'BEGIN{print "25fix"+0}'
25
SUN OS: SUNWesu $ /usr/bin/awk 'BEGIN{print "25fix"+0}'
0
SUN OS: SUNWxpg $ /usr/xpg4/bin/awk 'BEGIN{print "25fix"+0}'
25
查看更多
Ridiculous、
3楼-- · 2019-07-14 21:03

You can use the following awk script:

/:/ && $2 ~/ms$/{vals[$1]=vals[$1] OFS $2+0;next}
/:/ && $2 ~/[^m]s$/{vals[$1]=vals[$1] OFS ($2+0)*1000}
END {
         for (key in vals)
          print key vals[key]
}

This will produce the output:

awk -f try.awk file.txt 
Cache: 142 172
Searchms: 131 3200
RAM: 2000 184 149

Explanations:

  • The condition $2 ~/ms$/ will check if we have a line with ms in this case the same logic is done as before and the next will force awk to jump to the next line.
  • /:/ && $2 ~/[^m]s$/{vals[$1]=vals[$1] OFS ($2+0)*1000} when we reach this scope we know that we have a line with units in s and we multiply it by 1000 to convert it to ms.

To answer to your new requirements, I have adapted the try.awk into:

/:/ && $2 ~/[0-9]+s[0-9]+ms$/{split($2,buff,/s/);vals[$1]=vals[$1] OFS (buff[1]+0)*1000+buff[2];next}
/:/ && $2 ~/ms$/{vals[$1]=vals[$1] OFS $2+0;next}
/:/ && $2 ~/[^m]s$/{vals[$1]=vals[$1] OFS ($2+0)*1000}
END {
         for (key in vals)
          print key vals[key]
}

Input:

$ cat file2.txt 
Iteration 1
RAM: +2s342ms

Iteration 2
RAM: +2s

Iteration 3
RAM: +149ms

Output:

$ awk -f try.awk file2.txt 
RAM: 2342 2000 149
查看更多
登录 后发表回答