简体   繁体   中英

In AWK `rec=rec“,”$i` doesn't work as expected, where $i is each field in a record

I've my vmstat output on a linux box as such:

# cat vmstat.out
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 2675664 653028 3489156    0    0     1    19   22    7  5  1 94  0  0

I intend to keep the value under each field in a comma separated format along with timestamp(of course to use it as CSV file to be later transferred to our very loving MS Excel). So basically this is what I want:

Expected Output:

2016,05,19,23,53,58,1,0,0,2675664,653028,3489156,0,0,1,19,22,7,5,1,94,0,0

Script:

cat vmstat.out | awk 'BEGIN{"date +'%Y,%m,%d,%H,%M,%S'"| getline dt;}{if (NR> 2) {i=1;while (i < NF) {rec=rec","$i; i++;} print dt,rec;}}'

Output that I get from my script:

2016,05,19,23,53,58 ,1,0,0,2675664,653028,3489156,0,0,1,19,22,7,5,1,94,0

Note the extra space : 58 ,1 and the last 0 missing from Expected Output. I know the part in my script that is messing up is: rec=rec","$i

How to get around this ?

no need to reinvent awk features

$ awk -v OFS=, 'BEGIN{time=strftime("%Y,%m,%d,%H,%M,%S")} 
                 NR>2{$1=$1; print time,$0}' file

2016,05,19,15,12,29,1,0,0,2675664,653028,3489156,0,0,1,19,22,7,5,1,94,0,0

The extra space in 58 ,1 is because you're telling awk to print a space (OFS) between dt (which ends in 58 ) and rec (which starts with ,1 ) with the comma in print dt,rec , nothing to do with rec=rec","$i .

The missing last field is because you're telling awk to stop looping before the last field. Changing while (i < NF) to while (i <= NF) would have fixed that but the loop's not necessary at all (see below).

I'm assuming you don't have GNU awk or you'd be using strftime() instead of date .

Don't have shell call awk to call shell to call date and then a pipe to getline (which you're using unsafely btw, see http://awk.freeshell.org/AllAboutGetline ):

awk 'BEGIN{"date +'%Y,%m,%d,%H,%M,%S'"| getline dt;} {script}'

Just have shell call date :

awk -v dt=$(date +'%Y,%m,%d,%H,%M,%S') '{script}'

and after getting rid of the UUOC the full script is simply:

$ awk -v dt=$(date +'%Y,%m,%d,%H,%M,%S') -v OFS=, 'NR>2{$1=dt OFS $1; print}' vmstat.out
2016,05,19,14,53,05,1,0,0,2675664,653028,3489156,0,0,1,19,22,7,5,1,94,0,0

i <= NF will take care of the missing trailing 0.

Instead of looping over the fields, a more awk'ish way of doing the same thing is to set OFS - Output Field Separator to ",".

awk ' BEGIN{OFS="," ; "date +'%Y,%m,%d,%H,%M,%S'"| getline dt;} {if (NR> 2) {$1=$1 ; print dt,$0;}} ' vmstat.out

One small glitch with that is that awk doesn't reformat $0 until something is changed. Setting $1=$1 is enough to force awk to do that ( setting the output field separator in awk )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM