用AWK及Python求和及平均值

文件如下

# cat cesc 
a,1
a,2
b,3
b,4
c,2
d,5

需要获取abcd出现的次数,逗号后面数字的和及平均值。

With shell:

# grep -E ^a cesc |awk -F ',' '{sum+=$2} END {print "a, Count:" NR " Sum: " sum " Average: " sum/NR}'
a, Count:2 Sum: 3 Average: 1.5
# grep -E ^b cesc |awk -F ',' '{sum+=$2} END {print "b, Count:" NR " Sum: " sum " Average: " sum/NR}'
b, Count:2 Sum: 7 Average: 3.5
# grep -E ^c cesc |awk -F ',' '{sum+=$2} END {print "c, Count:" NR " Sum: " sum " Average: " sum/NR}'
c, Count:1 Sum: 2 Average: 2
# grep -E ^d cesc |awk -F ',' '{sum+=$2} END {print "d, Count:" NR " Sum: " sum " Average: " sum/NR}'
d, Count:1 Sum: 5 Average: 5

或者写成一个for循环,这样可移植性更好,另外,在awk中引用shell的变量有两种办法,一个是用双引号和单引号包含变量,如:”‘var'”,还有就是使用awk的-v参数提前声明,如:awk -v var=”$var”

# for i in `cat cesc |cut -d, -f1|sort|uniq`;do grep -E ^$i cesc |awk -F ',' '{sum+=$2} END {print "'$i'" " Count: " NR ", Sum: " sum ", Average: " sum/NR}';done
a Count: 2, Sum: 3, Average: 1.5
b Count: 2, Sum: 7, Average: 3.5
c Count: 1, Sum: 2, Average: 2
d Count: 1, Sum: 5, Average: 5

或者:

# for i in `cat cesc |cut -d, -f1|sort|uniq`;do grep -E ^$i cesc |awk -v i="$i" -F ',' '{sum+=$2} END {print i " Count: " NR ", Sum: " sum ", Average: " sum/NR}';done
a Count: 2, Sum: 3, Average: 1.5
b Count: 2, Sum: 7, Average: 3.5
c Count: 1, Sum: 2, Average: 2
d Count: 1, Sum: 5, Average: 5

 

 

With python:(python的整形除法默认地板除,只返回一个整形,可以使用from __future__ import division来实现真正的除法)

from __future__ import division

alist = []
blist = []
clist = []
dlist = []
for i in open('cesc'):
    ss = i.split(',')
    if ss[0] == 'a':
        alist.append(int(ss[1]))
    elif ss[0] == 'b':
        blist.append(int(ss[1]))
    elif ss[0] == 'c':
        clist.append(int(ss[1]))
    elif ss[0] == 'd':
        dlist.append(int(ss[1]))

print 'a, Count: ' + str(len(alist)) + ', Sum: ' + str(sum(alist)) + '. Average: ' + str(sum(alist)//len(alist))
print 'b, Count: ' + str(len(blist)) + ', Sum: ' + str(sum(blist)) + '. Average: ' + str(sum(blist)//len(blist))
print 'c, Count: ' + str(len(clist)) + ', Sum: ' + str(sum(clist)) + '. Average: ' + str(sum(clist)//len(clist))
print 'd, Count: ' + str(len(dlist)) + ', Sum: ' + str(sum(dlist)) + '. Average: ' + str(sum(dlist)//len(dlist))

 

awk命令学习笔记

语法:

awk [ -F re] [parameter...] ['prog'] [-f progfile][in_file...]
  参数说明:
-F re:允许awk更改其字段分隔符。

parameter: 该参数帮助为不同的变量赋值。

'prog': awk的程序语句段。这个语句段必须用单拓号:'和'括起,以防被shell解释。'prog'语句段的标准形式为:'pattern {action}'

pattern参数可以是egrep正则表达式中的任何一个,它可以使用语法/re/再加上一些样式匹配技巧构成。与sed类似,你也可以使用","分开两样式以选择某个范围。 

action参数总是被大括号包围,由awk语句组成,各语句之间用";"分隔。awk解释它们,并在pattern给定的样式匹配的记录上执行操作。你可以省略pattern和 action之一,但不能两者同时省略,当省略pattern时没有样式匹配,表示对所有行(记录)均执行操作,省略action时执行缺省的操作——print,在标准输出上显示。 

-f progfile:允许awk调用并执行progfile指定有程序文件。progfile是一个文本文件,他必须符合awk的语法,适合awk程序较大时使用。 

in_file:awk的输入文件,awk允许对多个输入文件进行处理。值得注意的是awk不修改输入文件。如果未指定输入文件,awk将接受标准输入,并将结果显示在标准输出上。awk支持输入输出重定向。

  记录、字段与内置变量: awk默认将一行视为一个记录,而字段指一行中的某一部分(由分隔符决定,默认为空格)。 $0用来表示一行记录,$1,$2…$n用来表示一行记录中的不同字段。   常用的内置变量有: NF (Number of Fields): 为一整数, 其值表$0上所存在的字段数目. NR (Number of Records): 为一整数, 其值表awk已读入的数据行数目. FILENAME: 正在处理的数据文件文件名.  

运算符:

赋值运算符
= += -= *= /= %= ^= **=	赋值语句

逻辑运算符
||	逻辑或
&&	逻辑与

正则运算符
~ ~!	匹配正则表达式和不匹配正则表达式

关系运算符
< <= > >= != ==	关系运算符

算术运算符
+ -	加,减
* / &	乘,除与求余
+ - !	一元加,减和逻辑非
^ ***	求幂
++ --	增加或减少,作为前缀或后缀

 


  测试文件内容如下,第一列为名称,第二列为时薪,第三列为工时。

Theo	5.10	12
Beth	4.00	0
Dan	3.75	11
Aaron	6.10	30
kathy	4.00	10
Mark	5.00	20
Mary	5.50	22
Susie	4.25	18
  获取每个人的总薪水(printf格式化输出,%6s表示长度为6的字符串,%3d表示长度为3的整数)
# awk '{ printf("%6s Work hours: %3d Pay: %5d\n", $1,$3, $2* $3) }' emp.data 
  Theo Work hours:  12 Pay:    61
  Beth Work hours:   0 Pay:     0
   Dan Work hours:  11 Pay:    41
 Aaron Work hours:  30 Pay:   183
 kathy Work hours:  10 Pay:    40
  Mark Work hours:  20 Pay:   100
  Mary Work hours:  22 Pay:   121
 Susie Work hours:  18 Pay:    76

  获取M开头的人的总薪水(~表示匹配,/^M.*/为正则表达式)

# awk '$1 ~ /^M.*/ { printf("%6s Work hours: %3d Pay: %5d\n", $1,$3, $2* $3) }' emp.data 
  Mark Work hours:  20 Pay:   100
  Mary Work hours:  22 Pay:   121

  获取工作时间大于等于20的人的名称(>=为操作符)

# awk '$3 >= 20 {print $1}' emp.data 
Aaron
Mark
Mary

  获取工作时间大于等于20且时薪小于等于5.5的记录(两个pattern,一个action,&&表示两个pattern的逻辑与操作)

# awk '$3 >= 20&&$2 <= 5.5 {print $0}' emp.data 
Mark	5.00	20
Mary	5.50	22

  获取工作时间大于等于20或时薪小于5的记录(两个pattern,一个action,||表示两个pattern的逻辑或操作)

# awk '$3 >= 20||$2 <= 5 {print $0}' emp.data 
Beth	4.00	0
Dan	3.75	11
Aaron	6.10	30
kathy	4.00	10
Mark	5.00	20
Mary	5.50	22
Susie	4.25	18

  给时薪小于等于4的人加薪10%并输出加薪后的记录(一个pattern,两个action)

# awk '$2 <= 4 {$2*=1.1} { printf("%6s %4s %5s\n",$1,$2,$3) }' emp.data 
  Theo 5.10    12
  Beth  4.4     0
   Dan 4.125    11
 Aaron 6.10    30
 kathy  4.4    10
  Mark 5.00    20
  Mary 5.50    22
 Susie 4.25    18

  给时薪小于等于4且工时大于等于10的人加薪10%并输出加薪后的记录(两个pattern,两个action)

# awk '$2 <= 4&&$3 >=10 {$2*=1.1} { printf("%6s %4s %5s\n",$1,$2,$3) }' emp.data 
  Theo 5.10    12
  Beth 4.00     0
   Dan 4.125    11
 Aaron 6.10    30
 kathy  4.4    10
  Mark 5.00    20
  Mary 5.50    22
 Susie 4.25    18

            参考: http://www.aslibra.com/doc/awk.htm http://www.cnblogs.com/chengmo/archive/2010/10/11/1847515.html http://net.pku.edu.cn/~yhf/tutorial/awk_manual.html http://awk.readthedocs.org/en/latest/chapter-one.html

使用awk,sed合并行

注意文件格式,确保是unix文件格式再操作

获得test.log文件中包含Accepting POP connection from的行的下第二行并打印第六项

awk '/Accepting POP connection from/{getline;getline;print $6}' test.log

获得test.log文件中包含Accepting POP connection from的行的下第二行

sed -n '/Accepting POP connection from/{p;n;n;p}' test.log

将test.log文件每两行合并为一行,如1,2一行;3,4一行;5,6一行。。。

awk '{printf (NR%2==0) ? $0"\n" : $0" "}' test.log