免费注册 查看新帖 |

Chinaunix

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

[文本处理] awk的疑惑 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-12-14 20:33 |只看该作者 |倒序浏览
本帖最后由 stractor 于 2014-12-14 20:40 编辑

      我才学awk。我有一个2160000行的数据文件,该文件记录原子坐标的x,y,z分量,原子数为108个,每一时刻保存了一组坐标,共20000个时刻点,那么这个文件的行数是108*20000=2160000。
      文件的1-108行为第1步(第1个时刻)108个原子的坐标,每个原子坐标为1行,109-216为第2步所有原子的坐标,依次类推。
      我想每隔10步提取一次坐标,即提取第1步,第11步,第21步,......。也就是提取第1-108行(第1步),第1081-1188行(第11步),第2161-2268行(第21步),.......。
      写了一个awk程序如下:

{
  for (i=1;i<=108;i++) {
       for (k=i;k<=2160000;k=k+1080) {
           if (NR==k) {
         print i, k, NR, $0
        }
      }  
    }
}

我很难理解脚本运行后的输出结果(后三列是原子坐标):
1  1  1  2.15279   2.15279 2.15279
2  2  2  2.15279   0.00000 0.00000
3  3  3  0.00000   2.15279 0.00000
4  4  4  0.00000   0.00000 2.15279
************** 中间省略100行
105  105  105 10.76393    10.76393        10.76393
106  106  106 10.76393    8.61114 8.61114
107  107  107 8.61114     10.76393        8.61114
108  108  108 8.61114     8.61114 10.76393
以上应该是第1个时刻108个原子的原子坐标。

接着输出
1 1081 1081 2.17063     2.22018 2.08864
2 1082 1082 2.26649     12.85895        12.90851
3 1083 1083 12.82804    2.27516 0.04992
4 1084 1084 12.91431    0.06733 2.18726
************** 中间省略100行
105 1185 1185 10.75824  10.77543        10.82052
106 1186 1186 10.75691  8.71706 8.60478
107 1187 1187 8.65212   10.66284        8.56873
108 1188 1188 8.63280   8.67194 10.90492
以上应该是第11个时刻点108个原子的坐标。

接着输出第21个时刻点原子的坐标
1  2161  2161 2.18957     2.28558 2.02208
2  2162  2162 2.37194     12.81356        12.90239
3  2163  2163 12.74656    2.39551 0.09872
4  2164  2164 12.91271    0.13585 2.21755
******************

我的理解是:i 是最外层循环,i从1开始,到108结束,应该输出一个i,再输出一些列的k(即内存循环和选择语句),也就是感觉会输出类似如下的结果:

1    1          1       X    X   X (X是原子的x, y, z坐标)
1    1081    1081  x     x   x
1    2161  2161    x     x   x
****** 以下省略

i 取1 输出k和NR后,i 开始 取2而输出
2     2       2      X    X    X
2    1082  1082  X    X    X
2    2162  2162 X    X    X
****** 以下省略
再输入i=3,直到 i=108。

我的脚本能完成我的要求吗?为何输出的结果是那样的?
求有经验的人帮助我一下。

论坛徽章:
0
2 [报告]
发表于 2014-12-14 21:39 |只看该作者
  1. awk '

  2.         NR>be && NR<=(be+108) {
  3.                 print NR,$0
  4.                 next
  5.         }
  6.        
  7.         NR == be +109{
  8.                 be += 108*10
  9.         }

  10. '
复制代码
题主,你脚本有个很大的问题,就是没有理解awk的运作方式。
awk 是对输入的每一行,进行操作,是面向行的(当然你要是改变NR的值就别说)。
你的那个for循环,是要对第一行的数据进行一次两重循环,第二行进行一次两重循环,,,,,,所以,,,,比如第一行
2.15279   2.15279 2.15279
NR=1,对这一行,i=1,k=i的时候,正好满足,于是输出了,然后循环接着进行,但后面的都不配,没有输出结果
对你输入的第二行,首先
i=1,k=1不匹配,
然后i=1;k=1080+1还是不匹配,然后循环,直到i=2,k=2,于是NR==k满足,输出。。。。

效率太低了。
我上面的脚本输出和你现在的输出是一样的,但效率应该要高。然后就是,我还是没明白你想要的输出结果是怎样的?

有不对的地方,请文明讨论。

论坛徽章:
0
3 [报告]
发表于 2014-12-15 10:02 |只看该作者
本帖最后由 Looiml 于 2014-12-15 10:18 编辑

不就是一句话的事儿吗?为什么要弄得那么复杂?
awk '{a=NR%1080;if(a>0&&a<109)print int(NR/1080)+1,a,$0}' file

论坛徽章:
0
4 [报告]
发表于 2014-12-15 16:08 |只看该作者
谢谢您的指点,我那个脚本的确很慢。我不确信是否理解了你的观点。
你是说awk是一行一行的处理,即NR优先,对每一个NR值(也就是每行),程序都要运行那两个循环,直到NR==k时就输出结果。
换句话说,就是NR=1,运行那2个循环,找出满足条件的行输出;然后NR=2,又开始那个循环,及 i 从1到108,对每一个i,再按我嵌套的循环取k,找出满足条件的行输出;然后NR=3,。。。。。。

请问,我的理解对吗?


回复 2# wcvolcano


   

论坛徽章:
0
5 [报告]
发表于 2014-12-15 16:30 |只看该作者
非常感谢。可以实现。
回复 3# Looiml


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP