免费注册 查看新帖 |

Chinaunix

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

如何实现将文件中相邻两行数据的运算? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-01-30 23:38 |只看该作者 |倒序浏览
比如有文件如下:
1371, 1605, 1251, 197
2294, 2289, 1873, 199
3133, 2838, 2605, 289
4287, 6010, 8478, 114
7546, 6816, 3958, 319
4652, 8779, 1972, 449


从第二行开始,将每一行的每一列的数值与前一行相应列的数值相减,生成如下文件:

923, 865,226,2
938, 549,382,90
....
....

我想用awk应该可以实现,但在AWK里不知道如何读出前一行的数据。各位大侠可有高招?

论坛徽章:
0
2 [报告]
发表于 2007-01-31 00:58 |只看该作者
#!/bin/sh
awk -F, '{
for (i=1;i<FNR;i++)
{
if (NR > 1)
{
$5=$1-var1
$6=$2-var2
$7=$3-var3
$8=$4-var4
}
var1=$1
var2=$2
var3=$3
var4=$4
}
print $5,$6,$7,$8}' cu.txt

我得到
2294 2289 1873 199
0       0        0       0
0       0        0       0
0       0        0       0
0       0        0       0


为什么?

论坛徽章:
0
3 [报告]
发表于 2007-01-31 09:22 |只看该作者
awk '{if(NR > 1){var5=$1 - var1;var6 = $2 - var2;var7 = $3 - var3;var8 = $4 - var4;print var5 var6 var7 var8}var1 = $1;var2 = $2;var3 = $3;var4 = $4}' urfile

[ 本帖最后由 Iambitious 于 2007-1-31 09:25 编辑 ]

论坛徽章:
0
4 [报告]
发表于 2007-02-03 13:06 |只看该作者
otask盒Iambitious的的看上去似乎是可行的。但在我运行了一下,返回的都是零。并且此语句的适用性不强,如果数据不是四列的话,就得重新修改。如果列数很多的话,就不可用了。

试了好几天,终于写出了我自己的版本:


  1. #!/bin/sh
  2. lines=`cat $1 | wc -l`
  3. result=`expr $lines / 2 \* 2`
  4. if [ $lines -eq $result ]; then         # lines is even
  5.         #awk -f awktest1 $1 > data1.txt
  6.         awk 'BEGIN{FS=","}{for(i=2;i<=NF;i++){a[i]=$i};
  7.                 getline
  8.                 for(j=2;j<=NF;j++){printf $j-a[j]"  "}
  9.                 print "\r"}' $1 > data1.txt
  10.         #sed -e '1d;$d' $1 | awk -f awktest1 > data2.txt
  11.         sed -e '1d;$d' $1 | awk 'BEGIN{FS=","}
  12.                                 {for(i=2;i<=NF;i++){a[i]=$i};
  13.                                 getline
  14.                                 for(j=2;j<=NF;j++){printf $j-a[j]"  "}
  15.                                 print "\r"}' > data2.txt
  16.         #awk -f awktest3 data1.txt | sed '$d' > data.txt
  17.         awk '{ print $0
  18.                 getline< "data2.txt"
  19.                 print $0
  20.                 }' data1.txt | sed '$d'
  21. else
  22.         sed -e '$d' $1 | awk 'BEGIN{FS=","}
  23.                                                 {for(i=2;i<=NF;i++){a[i]=$i};
  24.                                                 getline
  25.                                                 for(j=2;j<=NF;j++){printf $j-a[j]"  "}
  26.                                                 print "\r"}' > data1.txt
  27.         sed -e '1d' $1 | awk 'BEGIN{FS=","}
  28.                                                 {for(i=2;i<=NF;i++){a[i]=$i};
  29.                                                 getline
  30.                                                 for(j=2;j<=NF;j++){printf $j-a[j]"  "}
  31.                                                 print "\r"}' > data2.txt
  32.         awk '{ print $0
  33.                 getline< "data2.txt"
  34.                 print $0
  35.                 }' data1.txt
  36. fi

复制代码


脚本利用了AWK的getline能读取下一行的功能,可以同时读出两行数据,然后相减。如:
第一次读取:
$0 = line 1
getline = line2
但因为使用了getline之后,awk将对文件隔行读取,因此第二次读取的时候,情况如下:
$0 = line 3
getline = line 4
因此,当脚本运行完一次后,只计算了一半的数据,比如 line2 - line1, line 4 - line 3, ....
所以还需要对剩下的一半做处理,即把文件的第一行删除后,再做一次以上的处理,将会得到: line 3 - line 2, line 5 - line 4, ....

最后,将以上得出的各一半数据进行合并,即得到整个数据的结果。

很麻烦,是吧? 可是谁叫awk没有控制读取文件的指针呢,如果有的话,就方便多啦!

论坛徽章:
0
5 [报告]
发表于 2007-02-03 13:18 |只看该作者
看不出你给的例子数据是怎么回事...


  1. Administrator@EDENSXY ~
  2. $ echo '1371, 1605, 1251, 197
  3. 2294, 2289, 1873, 199
  4. 3133, 2838, 2605, 289
  5. 4287, 6010, 8478, 114
  6. 7546, 6816, 3958, 319
  7. 4652, 8779, 1972, 449' | awk -F',' 'BEGIN{print "------------"}
  8. NR == 1 { for (i = 1; i <= NF; i++) hash[i] = $i; }
  9. NR > 1{ for (i = 1; i <= NF; i++){
  10. printf("%d ", $i - hash[i]);
  11. hash[i] = $i;
  12. }
  13. printf("\n");
  14. }'
  15. ------------
  16. 923 684 622 2
  17. 839 549 732 90
  18. 1154 3172 5873 -175
  19. 3259 806 -4520 205
  20. -2894 1963 -1986 130

复制代码

论坛徽章:
0
6 [报告]
发表于 2007-02-03 13:22 |只看该作者
try
  1. awk '{
  2.         do {
  3.                 for (i = 1; i <= NF; i++) tmp[i] = $i;
  4.                
  5.                 if (getline <= 0) break;
  6.                
  7.                 for (i = 1; i <= NF; i++) printf($i - tmp[i] "\t");
  8.                
  9.                 printf("\n");
  10.         } while (1==1);
  11. }' urfile
复制代码

论坛徽章:
0
7 [报告]
发表于 2007-02-03 13:28 |只看该作者
各位都牛得很啊,sed我还知道一点,awk就说不上什么话来了。O'REILLY那本sed & awk前四章就学了好几个星期了。
打算寒假不窜门不拜年了,就学习20天awk

论坛徽章:
0
8 [报告]
发表于 2007-02-03 13:33 |只看该作者
原帖由 mmx384 于 2007-2-3 13:28 发表
各位都牛得很啊,sed我还知道一点,awk就说不上什么话来了。O'REILLY那本sed & awk前四章就学了好几个星期了。
打算寒假不窜门不拜年了,就学习20天awk



sed & awk那书不错...
第三章的正则, 如果你觉得自己正则水平够, 可以跳过, 里面讲了[^>]这个技巧的~~不过正则是基本功哈...

第五章也不难, 主要是sed基本语法. 第六章介绍的高级命令, 需要一些锻炼~~~
第七章介绍awk. 比较重要的一章, 开始看不明白, 别着急...多自己找练习...论坛上很多..以前有很多问题...^_^

论坛徽章:
0
9 [报告]
发表于 2007-02-03 13:54 |只看该作者
原帖由 Edengundam 于 2007-2-3 13:18 发表
看不出你给的例子数据是怎么回事...

[code]
Administrator@EDENSXY ~
$ echo '1371, 1605, 1251, 197
2294, 2289, 1873, 199
3133, 2838, 2605, 289
4287, 6010, 8478, 114
7546, 6816, 3958, 319
4652 ...


Wow! 太棒了!简洁明了,比我的好多了。砖果然引来了玉!呵呵。。

有一个问题,以下这句:
NR == 1 { for (i = 1; i <= NF; i++) hash = $i;

是一个判断语句吧? 如果NR=1,则执行后面的操作?  才知道awk有这样的语法!

谢谢!

BTW: 俺的数据只是个随便编的例子。实际的数据是一些网络接口的byte数,太大,不好弄上来。

论坛徽章:
0
10 [报告]
发表于 2007-02-03 14:01 |只看该作者
原帖由 awk就是awp加ak 于 2007-2-3 13:22 发表
try [code]awk '{
        do {
                for (i = 1; i <= NF; i++) tmp = $i;
               
                if (getline <= 0) break;
               
                for (i = 1; i <= NF; i++) printf($i - tmp "\t");
               
                printf("\ ...


这好像不行。结果如下:
jliut@~# awk '{
>         do {
>                 for (i = 1; i <= NF; i++) tmp = $i;
>
>                 if (getline <= 0) break;
>
>                 for (i = 1; i <= NF; i++) printf($i - tmp "\t");
>
>                 printf("\n");
>         } while (1==1);
> }' int_odd.txt
0       0
0       0
0       0
0       0
0       0
0       1
0       0
0       0
jliut@~#
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP