转载自:http://blog.chinaunix.net/uid-10540984-id-323936.html
分类: LINUX
这个特殊的for循环用于对数组的迭代
for ( a in b ) {...}
这段代码将打印数组 b 中的每一个元素 ,当对于 for 使用这种特殊的 "in" 形式时
awk 将 数组b的每个现有下标依次赋值给 a(循环控制变量),每次赋值以后都循环一次循环代码。他的缺点是 它不会依照任何特定的顺序。
- $ cat a
- 1 a
- 2 f
- 3 5
- 4 8
- $ cat b
- 1 a
- 2 f
- 3 5
- 5 8
有这么两个文本,要求以文本a的第一个字段为比较,如果文本b的第一个字段与a不符合,那么打印出该行。
- awk 'NR==FNR{a[$1];next}!($1in a)' a b
- 5 8
[解析]
首先NR==FNR对文本a进行处理,把$1的值作为下标放入数组a,next不会执行后面的语句,一直读到文本b不满足NR==FNR条件,这时判断文本b的$1是否存在于数组a中的下标中,显然文本b的第一行的$1是存在于数组a的下标中的,那么条件为真,再!,注意非真即为假,为假那么不会执行该pattern后面默认的{print]这个action动作,那么则不会输出该行,一直到第4行的$1并未存在于数组a的下标中,那么条件为假,非假为真,则执行默认的打印,输出了该行。或许下面的写法更符合规范和便于理解:
- awk 'NR==FNR{a[$1];next}{if(!($1in a))print $0}' a b
还有没有更简单的方法呢?有的,呵呵,利用pattern的特性,我写出了下面的语句,更短:
- awk 'NR==FNR{a[$1]=1;next}!a[$1]' a b
[解析]
给该数组赋予一个值为1,如果文本b的$1存在数组a中,那么数组a的值则为1,非真为假,则不输出,如果不存在数字a中,那么数组a的值是为0的,非假为真,则打印。
书上说:
NR,表示awk开始执行程序后所读取的数据行数.
FNR,与NR功用类似,不同的是awk每打开一个新文件,FNR便从0重新累计.
下面看两个例子:
1,对于单个文件NR 和FNR 的 输出结果一样的 :
# awk '{print NR,$0}' file1
1 a b c d
2 a b d c
3 a c b d
#awk '{print FNR,$0}' file1
1 a b c d
2 a b d c
3 a c b d
2,但是对于多个文件 :
# awk '{print NR,$0}' file1 file2
1 a b c d
2 a b d c
3 a c b d
4 aa bb cc dd
5 aa bb dd cc
6 aa cc bb dd
# awk '{print FNR,$0}' file1 file2
1 a b c d
2 a b d c
3 a c b d
1 aa bb cc dd
2 aa bb dd cc
3 aa cc bb dd
在看一个例子关于NR和FNR的典型应用:
现在有两个文件格式如下:
#cat account
张三|000001
李四|000002
#cat cdr
000001|10
000001|20
000002|30
000002|15
想要得到的结果是将用户名,帐号和金额在同一行打印出来,如下:
张三|000001|10
张三|000001|20
李四|000002|30
李四|000002|15
执行如下代码
#awk -F \| 'NR==FNR{a[$2]=$0;next}{print a[$1]"|"$2}' account cdr
注释:
由NR=FNR为真时,判断当前读入的是第一个文件account,然后使用{a[$2]=$0;next}循环将account文件的每行记录都存入数组a,并使用$2第2个字段作为下标引用.
由NR=FNR为假时,判断当前读入了第二个文件cdr,然后跳过{a[$2]=$0;next},对第二个文件cdr的每一行都无条件执行{print a[$1]"|"$2},此时变量$1为第二个文件的第一个字段,与读入第一个文件时,采用第一个文件第二个字段$2为数组下标相同.因此可以在此使用a[$1]引用数组。
本篇文章来源于 Linux公社网站(www.linuxidc.com) 原文链接:http://www.linuxidc.com/Linux/2012-05/61174.htm