免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5004 | 回复: 8
打印 上一主题 下一主题

[文本处理] awk中关于FNR和NR的例子,请高手赐教 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-07-24 17:17 |只看该作者 |倒序浏览
看到一个关于awk的案例,AIX下话说有两个数据文件,分别为
1.txt,内容:
0011AAA 200.00 20050321
0012BBB 300.00 20050621
0013DDD 400.00 20050622
0014FFF 500.00 20050401

2.txt,内容:
I0011  11111
I0012  22222
I0014  55555
I0013  66666

目的是利用awk命令,比较1.txt的1-4字符 和 2.txt的2-5 字符,如果相同,将2.txt 的第二列 与 1.txt 合并
需要取得效果如下:
0011AAA 200.00 20050321 11111
0012BBB 300.00 20050621 22222
0013DDD 400.00 20050622 66666
0014FFF 500.00 20050401 55555

命令是:
awk 'NR==FNR {a[substr($1,2,5)]=$2} NR>FNR && a[b=substr($1,1,4)] {print $0,a[b]}'  2.txt 1.txt

有没有awk高手能够详细解释一下上述命令的实现过程?谢谢了

论坛徽章:
0
2 [报告]
发表于 2012-07-24 17:17 |只看该作者
我自己是这么理解的
命令是:
awk 'NR==FNR {a[substr($1,2,5)]=$2} NR>FNR && a[b=substr($1,1,4)] {print $0,a[b]}'  2.txt 1.txt

将命令分为两个部分。
(1)先解析NR==FNR {a[substr($1,2,5)]=$2}
对于NR,读取行数分别为1234(2.txt),5678(1.txt)
对于FNR,读取行数分别为1234(2.txt),1234(1.txt)
因此NR==FNR的范围就在2.txt文件里了,substr函数得出的是:
a[0011]=$2=11111
a[0012]=$2=22222
a[0013]=$2=33333
a[0014]=$2=44444

(2)再来看NR>FNR && a[b=substr($1,1,4)] {print $0,a[b]}这一部分
NR>FNR的范围实在1.txt文件里,substr函数得出的是:
a[b=0011]
a[b=0012]
a[b=0013]
a[b=0014]
以上数组是在(1)中已经赋值了
再print $0,a[b],此处的$0是范围在1.txt里的

得出最后的结果

不知道我分析的过程对不对,还希望大家来指正

论坛徽章:
0
3 [报告]
发表于 2012-07-24 17:20 |只看该作者
最近在学习awk,有个高人总结的awk经验,贴出来跟大家分享:
awk的出错提示不怎么友好,经常报错让摸不着头脑,所以要对它的格式某些地方特别敏感!这里我根据经验特别说明如下几点:
1、awk 后面的语句一定要有两个’’ 包含起来!
2、一定要有一个文本的输入,可以放在后面,如本例的file,也可以通过管道符如|传给awk
如 ls |awk ‘{print $1}’ 这个时候的输入文件就是把ls的结果输给awk去处理!
3、-F参数是用来控制分割符的,比如 cat ljb.txt |awk –F “;” ‘{print $1,$2}’表示将ljb.txt文件中的内容的分号做为分割符,打印出第一列和第二列的值。这里要特别注意awk –F”;” 命令中,-F和”;”是没有空格的。
4、awk中的==表示等于,而=表示赋值,如果输错了,结果就完全错了。
比如 cat ljb.txt |awk ‘{if($3==6) print $0}’表示如果ljb.txt中默认以空格分割,假如第三列值为6,打印出来,如果这里将==写=,那就会打印出所有的值,其中第三列都被更新为6!
5、判断语句要有括号
如if($3==6)
6、这里我跳出AWK说一下SHELL,SHELL的[]中往往是判断,类似为
if [ $1=2 ]等,这里有别于awk,shell这个时候其实就是表示等于而不是赋值,如果你把=改写成两个=的==,那反而出错了,另外SHELL中也要留意,这里[]中的代码不能顶在[]的两边,如:[$1=2]或者是[$1=2 ]和[ $1=2]都是错误的!
7、整理了shell比较有别于其他编写程语句的一些特定脚本写法,现将awk 相关部分特别含义写法整理如下:
ARGC             命令行参数个数
ARGV             命令行参数排列
ENVIRON          支持队列中系统环境变量的使用
FILENAME         awk浏览的文件名
FNR               浏览文件的记录数
FS                设置输入域分隔符,等价于命令行- F选项
NF                浏览记录的域个数
NR                已读的记录数
OFS               输出域分隔符
ORS               输出记录分隔符
RS                控制记录分隔符

论坛徽章:
8
摩羯座
日期:2014-11-26 18:59:452015亚冠之浦和红钻
日期:2015-06-23 19:10:532015亚冠之西悉尼流浪者
日期:2015-08-21 08:40:5815-16赛季CBA联赛之山东
日期:2016-01-31 18:25:0515-16赛季CBA联赛之四川
日期:2016-02-16 16:08:30程序设计版块每日发帖之星
日期:2016-06-29 06:20:002017金鸡报晓
日期:2017-01-10 15:19:5615-16赛季CBA联赛之佛山
日期:2017-02-27 20:41:19
4 [报告]
发表于 2012-07-24 17:22 |只看该作者
NR==FNR处理第一个数据文件
NR>FNR处理其它数据文件

论坛徽章:
0
5 [报告]
发表于 2012-07-24 17:29 |只看该作者
回复 1# liangzij


    好长。。
只提一点:
NR表示总记录数
FNR表示当前文件记录数

简单的例子,A文件10行 B文件20行,awk xxxx命令  A B 的时候,NR和FNR同时计数,当处理完A文件的记录后(FNR=10,NR=10),FNR重置后(FNR=1,2...)重新为B文件计数,而NR继续累积(NR=11,12...)
所以NR==FNR就是只对第一个文件进行处理,NR>FNR就是只对后面的文件处理(不一定是第二个,也可以是第三个,看awk后面跟的文件个数)

论坛徽章:
0
6 [报告]
发表于 2012-07-25 08:35 |只看该作者
建议用FILENAME来对输入文件做区分

论坛徽章:
0
7 [报告]
发表于 2012-07-25 12:29 |只看该作者
FILENAME怎么区分呢?

论坛徽章:
0
8 [报告]
发表于 2012-07-25 12:31 |只看该作者
本帖最后由 personball 于 2012-07-25 12:32 编辑

回复 7# liangzij

举个例子。。
    awk 'FILENAME=="new.conf"{do sth...;next}{do sth...}' new.conf 1.conf 2.conf

源自:http://bbs.chinaunix.net/thread-3760955-1-1.html

论坛徽章:
0
9 [报告]
发表于 2012-07-25 12:37 |只看该作者
回复 8# personball


   谢谢 personball和其他朋友的帮忙
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP