awk之getline()函数运用
zoer@ubuntu:~$ cat data
1000
naughty 500
cc 400
zoer 100
zoer@ubuntu:~$ awk '{if(NR==1){next} print $1,$2}' data
naughty 500
cc 400
zoer 100
awk可使用shell的重定向符进行重定向输出,如:
$ awk '$1=100{print $1 > "output_file"}' file
上式表示如果第一个域的值等于100,则把它输出到output_file中。也可以用>>来重定向输出,但不清空文件,只做追加操作。
输入重定向需用到getline函数。getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内容,并给NF,NR和FNR等内建变量赋值。如果得到一条记录,getline函数返回1,如果到达文件的末尾就返回0,如果出现错误,例如打开文件失败,就返回-1。如:
$ awk 'BEGIN{"date"|getline d;split(d,a);print a[2]}'
执行linux的date命令,并通过管道输出给getline,然后再把输出赋值给自定义变量d,并以默认空格为分割符把它拆分开以数字1开始递增方式为下标存入数组a中,并打印数组a下标为2的值。下面我们再看看一些复杂的运用。
1)
文件a
220 34 50 70
553 556 32 21
1 1 14 98 33
文件b
10
8
2
要求文件a的每行数据与文件b的相对应的行的值相减,得到其绝对值。
awk '{getline j<"b";for(i=1;i<=NF;i++){$i>j?$i=$i-j:$i=j-$i}}1' a|column -t
210 24 40 60
545 548 24 13
1 1 12 96 31
[解析]
getline依次按行读取文件b里的值,然后for循环依次和文件a里的每个字段进行比较,如果比它大就j-$i,要是比它小就$i-j,保证文件相减都是整数,当然更法很多,可以判断是否小于0,小于0就负负为正,也可以替换到负号这个符号等等。总结的说getline函数可以实现2个文件的同步读取而实现一系列的操作。下面是数组的解法:
awk 'ARGIND==1{a[FNR]=$1;next}{for(i=1;i<=NF;i++)$i=$i-a[FNR];$0=gensub(/-/,"","g")}1' b a
2)
文件a
aaa
bbb
ccc
ddd
文件b
111 xxx
222 xxx
333 xxx
444 xxx
要求文件a里的数据依次替换文件b中的xxx字样。
awk '{getline i<"a"}/xxx/{sub("xxx",i,$2)}1' b
111 aaa
222 bbb
333 ccc
444 ddd
[解析]
相信大家已经熟悉getline的用法了吧。呵呵,再看看数组的用法,数组是awk的灵魂,但是有点耗费资源,特别是数百兆上G文件的时候,它挺费劲,大家酌情考虑。
awk 'NR==FNR{a[FNR]=$1;next}/xxx/{++i;$2=a[i]}1' a b