linux汇总整理-awk篇

前言

注1:本文所用到的两个测试文件 user、consumer,分别模拟两张 SQL 表,其数据如下
注2:在生成文件时使用了特殊分隔符,文件见附件。

注意事项

  • 在awk中调用系统变量必须用单引号,如果是双引号,则表示字符串
Flag=abcd 
awk '{print '$Flag'}'   # 结果为abcd 
awk '{print  "$Flag"}'   # 结果为$Flag

使用举例

# 用tab做分隔符,并按列显示
awk -F '\x0001' '{print $1"\t"$2"\t"$3}' user | column -t 
# 对a.txt文件的第四个域进行求和
awk 'BEGIN{total=0}{total+=$4}END{print total}' a.txt   
# 打印所有以模式no或so开头的行
awk '/^(no|so)/' test
# 如果记录以n或s开头,就打印这个记录
awk '/^[ns]/{print $1}' test
# 如果第一个域以两个数字结束就打印这个记录
awk '$1 ~/[0-9][0-9]$/(print $1}' test
# 如果第一个或等于100或者第二个域小于50,则打印该行
awk '$1 == 100 || $2 < 50' test
# 如果第一个域不等于10就打印该行
awk '$1 != 10' test
# 如果记录包含正则表达式test,则第一个域加10并打印出来
awk '/test/{print $1 + 10}' test
# 如果第一个域大于5则打印问号后面的表达式值,否则打印冒号后面的表达式值
awk '{print ($1 > 5 ? "ok "$1: "error"$1)}' test
# 打印以正则表达式root开头的记录到以正则表达式mysql开头的记录范围内的所有记录。
# 如果找到一个新的正则表达式root开头的记录,则继续打印直到下一个以正则表达式mysql开头的记录为止,或到文件末尾
awk '/^root/,/^mysql/' test

awk可以实现类似sql语句的效果

  • 查询整张表记录,where 条件过滤,关键词:where
select * from user;
awk -F '\x0001' '{print}' user 
select * from consumer where cost > 100; 
awk -F '\x0001' '{if($2>100){print}}' consumer
select * from consumer where date like '201212';
awk -F '\x0001' '{if(substr($3,1,6)=="201212"){print }}' consumer 
  • 对某个字段去重,或者按记录去重,关键词:distinct
select distinct date from consumer;
awk -F '\x0001' '!a[$3]++{print $3}' consumer 
select distinct id, cost, date from consumer;
awk -F '\x0001' '!a[$1,$2,$3]++{print$1,$2,$3}' consumer
select distinct(*) from consumer;
awk -F '\x0001' '!a[$0]++{print}' consumer
  • 记录按序输出,关键词:order by
select id from user order by id;
awk '{a[$1]}END{asorti(a);for(i=1;i<=length(a);i++){print a[i]}}' user  感觉不对
  • 分组求和统计,关键词:group by、having、sum、count
select count(*),sum(cost) from consumer;
awk -F '\x0001' 'BEGIN{sum=0;count=0}{sum+=$2;count+=1}END{print sum,count}' consumer 
select count(*),sum(cost) from consumer where date like '201211%';
awk -F '\x0001' 'BEGIN{sum=0;count=0}{if(substr($3,1,6)=="201211"){sum+=$2;count+=1}}END{print sum,count}' consumer
select id, count(1), sum(cost) from consumer group by id having count(1) > 2;
awk -F '\x0001' '{a[$1]=a[$1]==""?$2:a[$1]","$2}END{for(i in a){c=split(a[i],b,",");{sum=0;for(j in b){sum+=b[j]};print i"\t"c"\t"sum}}}' consumer 该命令比较复杂,但是很考验awk的复杂应用技能,对该命令的解释如下:
    第一步:了解split函数的作用
    awk '{}END{a=split("2|1|3|1|4",b,"|");{print a}}' consumer 
    awk '{}END{a=split("2|1|3|1|4",b,"|");for(i in b){print b[i]}}' consumer
  可见split的作用是将指定的序列根据特定字符转变成数组,其返回值是该数组内容的个数
    第二步:了解a[$1]=a[$1]==""?$2:a[$1]","$2的作用
    awk -F '\x0001' '{a[$1]=a[$1]==""?$2:a[$1]","$2}END{for(i in a){print i"\t"a[i]}}' consumer
    可见其作用是将id和cost这两列组合成了一个比较复杂的数组。
    综上:该命令的作用就是先将id和cost的值组合成一个复杂的数组,然后再对这个数组加以处理。
  • 模糊查询,关键词:like(like属于通配,也可正则 REGEXP)尚未整理
select name from user where name like 'wang%';
awk '$2 ~/^wang/{print $2}' user
select addr from user where addr like '%bei';
awk '/.*bei$/{print $3}' user
select addr from user where addr like '%bei%';
awk '$3 ~/bei/{print $3}' user
  • 多表 join 关联查询,关键词:join
select a.* , b.* from user a inner join consumer b on a.id = b.id and b.id = 2;
awk 'ARGIND==1{a[$1]=$0;next}{if(($1 in a)&&$1==2){print a[$1]"\t"$2"\t"$3}}' user consumer
  • 多表水平联接,关键词:union all
select a.* from user a union all select b.* from user b;
awk 1 user user
select a.* from user a union select b.* from user b;
awk '!a[$0]++' user user
  • 随机抽样统计,关键词:order by rand()
SELECT * FROM consumer ORDER BY RAND() LIMIT 2;
awk 'BEGIN{srand();while(i<2){k=int(rand()*10)+1;if(!(k in a)){a[k];i++}}}(NR in a)' consumer
  • 行列转换,关键词:SUM(IF())、WITH ROLLUP
    mysql 写法:http://my.oschina.net/leejun2005/blog/77796
    awk 写法:http://hi.baidu.com/leejun_2005/item/2bac30c2b97e5e56ad00ef86

问题:如何删除大文件中的重复行,只保留不重复的?

  • 采用awk,只要一行:
    awk '{ if (!seen[$0]) print $0; seen[$0]++ }’
  • 更简洁写法
    这个例子中的字符串 seen 是一个关联数组的名字。$0 是一个变量,表示整个当前行。所以,这个命令翻译成人类语言就是“对这个文件的每一行进行检查,如果你之前没有见过它,就打印出来。” 如果该关联数组的键名还不存在就添加到数组,并增加其取值,这样 awk 下次遇到同样的行时就会不匹配(条件判断为“假”),从而不打印出来。
    awk '!seen[$0]++' <filename>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值