LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
楼主: jiazhengw

多发发一些有意思的题做做呀![+sed/awk/regex练习]

[复制链接]
发表于 2006-3-1 22:58:12 | 显示全部楼层
一个字: 好贴!
回复 支持 反对

使用道具 举报

发表于 2006-3-2 02:15:14 | 显示全部楼层
Awk vs SQL (Using awk to process Database Tables)

There are two tables. The first table is like:

  1. KeyID   Last Name       First Name      SSN     Phone Number        Address     Emergency Contact       Relationship
  2. -----------------------------------------------------------------------------------------------------------------------
  3. 1       Doe             John       12345678     111-222-3456        127 Main st.    John tyler          Sister
  4. 2       Mercurio        Dan        11223456     222-202-4566        Tower Stu 510
  5. 3       Tobin           Bruce      12334556                                         Kevin King          Friend
复制代码


The second table is like:

  1. Name            Jan     Feb     Mar     Apr     May     Jun     Jul     Aug     Sep     Oct     Nov     Dec
  2. ------------------------------------------------------------------------------------------------------------------
  3. John Doe       $51.95  $20.03   $11.8   $10.05          $3.2    $120.98 $538.39 $538.39         $20.03  $10.05
  4. Dan Mercurio                            $2.03   $5.27   $4.26   $42.10  $10.05  $227.30 $10.05  $12.98  $2.03
  5. Bruce Tobin    $4.98   $3.05    $31.2   $2.04   $2.04   $55.98          $1.08           $20.8           $250.98
复制代码

这两张表是某家医院数据库中对每个病人每年的医疗花销的记录,现在要打进出来一张汇总表格式如下:

  1. Name                SSN         Phone Number        Emergency Contact       Avg
  2. ------------------------------------------------------------------------------
  3. John Doe            12345678    111-222-3456        John tyler              $110.45
  4. Dan Mercurio        11223456    222-202-4566        N/A                     $26.34
  5. Bruce Tobin         12334556    N/A                 Kevin King              $31.01
复制代码

要求:
1. 用gawk来做(sed好象也做不了,呵呵)
2. Avg的计算结果保留两位小数,四舍五入。
附:各个单元格的数值长度定义
keyID: 8
Last Name: 10
First Name: 10
SSN: 8
Phone Number: 12
Address: 100
Emergency Contact: 20
Relationship: 20
Name: 20
Month: 10
Avg: 10
回复 支持 反对

使用道具 举报

发表于 2006-3-2 10:41:51 | 显示全部楼层
我写了个很笨的程序,因为我刚刚接触shell,里面的好多命令还不熟悉,呵呵,下面的程序还有个要求无法满足,输出结果中各个命令和解释之间没有1行空格分开,希望大家能帮忙改进一下。

  1. more  change.sh
  2. #!/bin/bash
  3. sed 's/^ *//g' second >sort
  4. a=`more sort |wc -l`
  5. b=1
  6. j=1
  7. for((i=1; i<=$a; i++))
  8. do
  9. sed -n ''$i'p' sort> sort1
  10. string=`sed 's/^$//g' sort1`
  11. if [ -z  "$string" ];
  12. then
  13.     b=`expr $i - 1`
  14.     sed -n ''$b'p' sort> sort1
  15.     string=`sed 's/^$//g' sort1`
  16.     if [ ! -z  "$string" ];
  17.     then
  18.      c=`sed -n ''$i'p' sort`
  19.      echo "" >> file$j
  20.      echo -n $c >> file$j
  21.      j=`expr $j + 1`
  22.     fi
  23. else
  24.    c=`sed -n ''$i'p' sort`
  25.    echo -n $c >> file$j
  26. fi
  27. done
  28. rm sort*
  29. sed -n 's/.*/&:/p' first> third
  30. a=`more first |wc -l`
  31. for((i=$a; i>=1; i--))
  32. do
  33. sed ''$i' r file'$i'' third > trans
  34. cp trans third
  35. done
  36. rm file*
  37. rm trans
  38. rm first1
  39. more third
复制代码


  1. ./change.sh
复制代码
回复 支持 反对

使用道具 举报

发表于 2006-3-2 11:52:37 | 显示全部楼层

小弟先来试一试

假设第一个table的文件名为userinfo,第二个table的文件名为account



  1. # search.a

  2. {

  3. if ($0!~/\w/) next        # exclude non-content line

  4. sum=0
  5. count=0
  6. contact=""

  7. while (getline name < "account") {
  8.         if (match(name,$3" "$2)) {
  9.                 split(name,a,"$")
  10.                 for (i in a) {
  11.                         if (a[i]!~/[a-zA-Z]/) { sum=sum+a[i]; count+=1 }
  12.                 }
  13.                 break
  14.         }
  15. }

  16. close("account")

  17. if ($5 && $5!~/[a-zA-Z]/) {
  18.         phone=$5
  19.         for (i=6;i<NF;i++) contact=(contact?contact" ":"")$i
  20. } else {
  21.         phone="N/A"
  22.         for (i=5;i<NF;i++) contact=(contact?contact" ":"")$i
  23. }


  24. print $3" "$2"\t"$4"\t"(phone == "N/A"?phone"\t\t":phone"\t")(contact?contact"\t":"N/A\t\t")sprintf("%.2f",sum/count)

  25. }


复制代码



  1. bash# awk 'BEGIN { FS="[0-9]+ [a-zA-Z]* [a-zA-Z.]*" } { print $1,$2 }' userinfo | awk -f search.a

复制代码


小弟程序先通过把地址栏作为FS,取出需要使用的部分,放弃地址栏的内容.接着把相关内容在进行处理.小弟的程序有以下弊端:

1.如果地址栏的地址格式不固定,那就会产生错误
2.如果有一个人的名字全是用数字表示(我想不太可能吧)就会有错误输出
3.最后print出来的格式只是适用针对当前这个实际的例子

总结:小弟这个程序通用性不强 ---> 小弟水平不够
回复 支持 反对

使用道具 举报

发表于 2006-3-2 12:12:38 | 显示全部楼层
以地址栏作为FS是基本上取巧的方法,实际上地址是不一样的,所以实用性大打折扣。但作出这样的已经很不错了。
回复 支持 反对

使用道具 举报

发表于 2006-3-2 12:45:23 | 显示全部楼层
1.有个问题想请教yongjian兄.在awk中,如果有个数组,内容如下

a[1]=1
a[2]=2
a[3]=3
...
a[7]=7

for (i in a) print i

为什么i总是从4开始,结果变成了
4
5
6
7
1
2
3

2.那个TEXTDOMAIN内置变量有点不太理解怎么使用的?:ask
回复 支持 反对

使用道具 举报

发表于 2006-3-2 13:50:10 | 显示全部楼层
你那不是shell吧?
回复 支持 反对

使用道具 举报

发表于 2006-3-2 14:22:28 | 显示全部楼层
Post by dunerunner
你那不是shell吧?


不是,是awk,shell的for不是这样写的
回复 支持 反对

使用道具 举报

发表于 2006-3-2 17:11:33 | 显示全部楼层
Post by johnny_jiang
1.有个问题想请教yongjian兄.在awk中,如果有个数组,内容如下

a[1]=1
a[2]=2
a[3]=3
...
a[7]=7

for (i in a) print i

为什么i总是从4开始,结果变成了
4
5
6
7
1
2
3

2.那个TEXTDOMAIN内置变量有点不太理解怎么使用的?:ask
我也遇到了同样的问题.
回复 支持 反对

使用道具 举报

发表于 2006-3-2 17:40:48 | 显示全部楼层
我查了点资料,资料上说这是awk的一个缺点,当 awk 在数组下标之间轮转时,它不会依照任何特定的顺序。也就是说使用for (i in a) print i时,输出的结果是没有什么规律的,即便是从4开始的结论也应该是错误的,它只是用i把a中的值轮转一遍.
回复 支持 反对

使用道具 举报

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

本版积分规则

快速回复 返回顶部 返回列表