awk 与 shell 交互方式

写了很长时间脚本,awk这块遇到过很多问题,下面这三个问题解决后
再也没有遇到过什么大的困难(至少目前),后来很多次割接,数据割接部分我都是用awk来做,比c,c++方便100倍

一、awk 与 shell 交互方式
在平时写脚本的过程中, awk 与 shell的交互不可避免的, shell比较强大, 但在处理一些事情时使用awk比较方便,
例如:
1、shell不支持小数点运算, awk支持
2、awk以字段的方式处理数据非常强大
3、awk处理文件关联比较方便
等等
下面列出几种常用的关联方式:

a、管道交互
这种方式最常见,举几个例子(个人写脚本喜欢换行,ksh可支持):

a.1:kill进程:
ps -ef | grep MonitorFrame | grep -v grep |
awk '
{
print "kill -9",$2;
}
'|sh

a.2: 清楚共享内存:
ipcs | grep gzngcrm |
awk '
{
  if($1=="s"){
    print "ipcrm", "-S", $3;
  }
  if($1=="m"){
    print "ipcrm", "-M", $3;
  }
}' | sh

a.3: 删除一个目录下的大量文件
当一个目录下的文件数过多时, rm *  会报入参超过数量
一般可以这样处理 ls | xargs rm
但如果文件名中含有空格, 比如我们的dump文件: 如MVPMNACCEPT_IVPMNSO_BAVDFQ06 - OUT - 2010-09-26 17-30-59.15-4492.dump
这时就需要awk了
ls | awk '{ print "rm", "\""$0"\"";}'|sh

b、变量交互
举例:
shell脚本在运行的过程中,得到了变量$m, $n的值,  需要求$m/$n  , 但shell并不支持小数运算, 传入给awk计算
有两种方式:
b.1: -v 方式
awk -v mm="$m" -v nn="$n" '
BEGIN{
print mm/nn; 
}
' | read c
echo $c;

b.2:"'$变量'" 方式
awk '
BEGIN{
print "'$m'"/"'$n'";
}
'| read c
echo $c

c、awk内部的交互
awk '
BEGIN{
while("ls|sort"|getline name){
  print "hello"name|"sort"
}
}
'

二、delete 回收内存
08年的时候, 局方提出了个很变态的提数需求, 记得是提07年12月到08年11月之间的广州全球通用户欠费情况
还要求附上相关的其他不着边际的信息, 总之要关联很多张表, 又不让直接在数据库中操作,怕影响数据库,
当时遇到了一个需要及时回收内存的操作, 大概如下:
输入:
subsid|validbillcyc|amt|
111|200712|50
111|200802|30
222|200801|20
111|200801|100
111|200802|50
222|200711|20
111|200712|20
111|200711|20 
这里只列举其中两个用户,实际文件相当庞大。
要求输出:
subsid|200712|200801|200802|
111|90|100|80|
222|20|20|0|
计算出每个用户200712月以前的欠费(含12月), 200801月欠费, 200802月欠费
按照常规按subsid&validbillcyc 建hash进行累加, 这样速度会慢的不得了
当时有个现成的归并排序工具, 可按其中一列进行排序, 所以进行排序(如下)
因此可以排队累加(按 subsid + validbillcyc)
111|200712|50
111|200802|30
111|200801|100
111|200802|50
111|200712|20
111|200711|20  --对111用户来说, 每次累加只需要累加到这里
222|200801|20
222|200711|20  --同样
111用户的累加结果为:
money[111|200712] = 90;
money[111|200802] = 80;
money[111|200801] = 100;
输出:
111|90|100|80|
按道理这样做就没有问题了, 但做的过程中,报内存不够
数据量非常大, 脚本在往下处理的过程中, 并没有及时释放之前的 money[xxx|YYYYMM] 的内存
因此需要及时释放内存:
for(i in money){
delete money ;
}

---脚本:
awk -F\| '
BEGIN{
        print "subsid|200712|200801|200802|";
}
{
  if(NR==1){
          onesubsid = $1;
          if($2 <= "200712"){
                  money[onesubsid"|200712"] += $3;
          }
          else{
                  money[onesubsid"|"$2] += $3;
          }       
  }     
  else{
          if(onesubsid == $1){
                  if($2 <= "200712"){
                          money[onesubsid"|200712"] += $3;
                  }
                  else{
                          money[onesubsid"|"$2] += $3;
                  }       
          }
          else{
                  money200712 = money[onesubsid"|200712"];
                  money200801 = money[onesubsid"|200801"];
                  money200802 = money[onesubsid"|200802"];
                 
                  printf("%s|%.3f|%.3f|%.3f|\n",onesubsid,money200712,money200801,money200802);
                 
                  for(i in money){
                          delete money;
                  }
                 
                  onesubsid = $1;
                  if($2 <= "200712"){
                          money[onesubsid"|200712"] += $3;
                  }
                  else{
                          money[onesubsid"|"$2] += $3;
                  }
          }
  }
}
END{
        money200712 = money[onesubsid"|200712"];
        money200801 = money[onesubsid"|200801"];
        money200802 = money[onesubsid"|200802"];
                 
        printf("%s|%.3f|%.3f|%.3f|\n",onesubsid,money200712,money200801,money200802);
 
  for(i in money){
                          delete money;
                  }
}
' unwoffcust

三、大文件关联
文件1格式: subsid|recamt|
文件2格式: subsid|servnumber|
输出:        subsid|recamt|servnumber|
把文件1读入内存,建立hash  money[subsid]=recamt
然后逐行读文件2, 根据subsid去money中找就可以了
问题在于文件1和文件2都非常庞大, awk所支持的hash不能支持    --这里就体现了perl的优势,但perl用的人太少

解决方法:
将文件1,文件2 都按subsid排序
从文件1中读入1行, 然后去文件2中找,如果小(继续往下找), 如果相等(找到,下次从文件2的这里的下一行开始找),
如果大(没找到,下次从文件2这里开始找)
文件1  文件2
100|10  98|13611111111  --100从这里开始
102|20  99|13611111111
105|30  100|13611111111  --找到
            101|13611111111  --102从这里开始
            103|13611111111  --没找到, 105从这里开始
            104|13611111111
            105|13611111111  --找到

awk -F\| -v subsfile='cm_subs_subscriber' '
BEGIN{
        getline < subsfile;                                        #:  $0, $1, $2
        subsid = $1;
        senumr = $2;
}
{
        this_subsid = $1;
        this_amt    = $2;
       
        while(this_subsid > subsid){                #$1,$2 取最新的一次读入的值
                getline < subsfile;
                subsid = $1;
                senumr = $2;
        }
       
        if(this_subsid == subsid){
                printf("%s|%s|%s|\n",this_subsid,this_amt,senumr);
        }
        else{
                printf("%s|%s|%s|\n",this_subsid,this_amt,"-1");
        }
}
' ib_cb_unwoffcust > ib_cb_unwoffcust_servnumber

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值