Linux文本搜索(三)之 awk

AWK

一般用于对文本内容进行统计、按需要的格式进行输出

AWK脚本的流程控制

  • 输入数据前例程BEGIN{}
  • 主输入循环{}
  • 所有文件读取完成例程END{}

AWK的字段

  • 每行称作AWK的记录
  • 使用分隔符(默认是空格)分割开的单词称作字段(下标从1开始)
  • 可以自己指定分隔符
  • awk中使用$0表示一条记录,$1 $2 $3 … $n 表示每一个字段
  • 使用-F 改变字段分隔符
使用逗号作为分隔符
awk -F ','  '{print $1,$2}' filename  

可以使用正则表达式作为分隔符

[root@bigdata grub2]# awk '/^###/{print $0}' /boot/grub2/grub.cfg
### BEGIN /etc/grub.d/00_header ###
### END /etc/grub.d/00_header ###
### BEGIN /etc/grub.d/00_tuned ###
### END /etc/grub.d/00_tuned ###
### BEGIN /etc/grub.d/01_users ###
### END /etc/grub.d/01_users ###
### BEGIN /etc/grub.d/10_linux ###
### END /etc/grub.d/10_linux ###
### BEGIN /etc/grub.d/20_linux_xen ###
### END /etc/grub.d/20_linux_xen ###
### BEGIN /etc/grub.d/20_ppc_terminfo ###
### END /etc/grub.d/20_ppc_terminfo ###
### BEGIN /etc/grub.d/30_os-prober ###
### END /etc/grub.d/30_os-prober ###
### BEGIN /etc/grub.d/40_custom ###
### END /etc/grub.d/40_custom ###
### BEGIN /etc/grub.d/41_custom ###
### END /etc/grub.d/41_custom ###
[root@bigdata grub2]# awk '/^###/{print $3}' /boot/grub2/grub.cfg
/etc/grub.d/00_header
/etc/grub.d/00_header
/etc/grub.d/00_tuned
/etc/grub.d/00_tuned
/etc/grub.d/01_users
/etc/grub.d/01_users
/etc/grub.d/10_linux
/etc/grub.d/10_linux
/etc/grub.d/20_linux_xen
/etc/grub.d/20_linux_xen
/etc/grub.d/20_ppc_terminfo
/etc/grub.d/20_ppc_terminfo
/etc/grub.d/30_os-prober
/etc/grub.d/30_os-prober
/etc/grub.d/40_custom
/etc/grub.d/40_custom
/etc/grub.d/41_custom
/etc/grub.d/41_custom

AWK的表达式

  1. 赋值操作符
  • =++--+=-=*=/=%=^=
var1 = "name"
var2 = "hello" "world"
var3 = $1
  1. 算术操作符
  • +-*/%^
  1. 系统变量
  • FS和OFS字段分隔符、OFS表示输出的字段分隔符
  • RS 记录分隔符 默认是\n
  • NR 和 FNR 行数,FNR会根据文件进行更新 eg: 两个文件 使用NR会从1往后累加,使用FNR,不同的文件会从1开始
  • NF 字段数量,最后一个字段内容可以用$NF取出
[root@bigdata /]# head -5 /etc/passwd | awk 'BEGIN{FS=":"}{print $1}'
root
bin
daemon
adm
lp
[root@bigdata /]# head -5 /etc/passwd | awk -F ":" '{print $1}'
root
bin
daemon
adm
lp
[root@bigdata /]# head -5 /etc/passwd | awk 'BEGIN{FS=":";OFS="#"}{print $1,$2}'
root#x
bin#x
daemon#x
adm#x
lp#x


[root@bigdata /]# awk '{print NR,$0}' /etc/hosts /etc/hosts
1 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
2 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
3 
4 192.168.0.3 bigdata
5 
6 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
7 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
8 
9 192.168.0.3 bigdata
10 
[root@bigdata /]# awk '{print FNR,$0}' /etc/hosts /etc/hosts
1 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
2 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
3 
4 192.168.0.3 bigdata
5 
1 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
2 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
3 
4 192.168.0.3 bigdata
5 

[root@bigdata /]# awk '{print NF}' /etc/hosts
5
5
0
2
0
  1. 关系操作符
  • <><=>===!=~!~
  1. 布尔操作符
  • && || !

AWK判断和循环

  1. 条件语句
[root@bigdata tmp]# cat kpi.txt 
user1 85 94 75 85 95 96
user2 75 84 85 95 95 96
user3 95 84 85 75 95 96
user4 74 75 85 75 95 96
user5 74 79 85 75 95 96
[root@bigdata tmp]# awk '{if($2 > 80) print $1}' kpi.txt 
user1
user3
# 满足条件要执行多条语句使用{}括起来
[root@bigdata tmp]# awk '{if($2 > 80) {print $1;print $2}}' kpi.txt 
user1
85
user3
95

[root@bigdata tmp]# awk '{if($2 > 80) {print $1;print $2} else print $0}' kpi.txt 
user1
85
user2 75 84 85 95 95 96
user3
95
user4 74 75 85 75 95 96
user5 74 79 85 75 95 96

  1. 循环
  • while
while(表达式)
	awk语句

  • do … while
do {
	awk语句
} while(表达式)

  • for循环
for(初始值;循环判断条件;累加)
	awk语句
eg

[root@bigdata tmp]# head -1 kpi.txt | awk '{for(c=2;c<=NF;c++) sum+=$c;print sum}'
530

[root@bigdata tmp]# awk '{sum=0;for(c=2;c<=NF;c++) sum+=$c;print sum}' kpi.txt 
530
530
530
500
504
  • break 与 continue

AWK数组

  1. 数组定义
数组名[] = 值
下标可以是数字也可以是字符串
  1. 数组的遍历
for(变量 in 数组名)
变量是指数组的下标
[root@bigdata tmp]# awk '{sum=0;for(c=2;c<=NF;c++) sum+=$c;avg[$1]=sum/(NF-1)}END{for(user in avg) sum2 += avg[user];print sum2/NR}' kpi.txt 
86.4667
  1. 删除数组
delete 数组名
delete 数组名[下标]
  1. 命令行参数数组
  • ARGC 参数的个数
  • ARGV 参数的值
[root@bigdata tmp]# cat arg.awk 
BEGIN{
    for(x=0;x<ARGC;x++)
	print ARGV[x]
    print ARGC
}
[root@bigdata tmp]# awk -f arg.awk 11 22 33
awk  下标0
11     下标1
22     下标2
33     下标3
4       #   命令也会记一个数

综合例子

[root@bigdata tmp]# cat result.awk 
{
sum = 0;
for(column=2;column<=NF;column++)
    sum += $column

avg[$1] = sum / (NF-1)

if(avg[$1] >= 80)
    level="s"
else if(avg[$1] >= 70)
	level="a"
else if(avg[$1] >= 60)
        level="b"
else
    level="c"

print $1,avg[$1],level

level_all[level]++


}
END{

for(user in avg)
    sum_all += avg[user]
avg_all=sum_all / NR

print "avg_all",avg_all

for(user in avg)
    if(avg[user] > avg_all)
	above++
    else
	below++

print "above",above
print "below",below
print "s:",level_all["s"]
print "a:",level_all["a"]
print "b:",level_all["b"]
print "c:",level_all["c"]
}
[root@bigdata tmp]# awk -f result.awk kpi.txt 
user1 88.3333 s
user2 88.3333 s
user3 88.3333 s
user4 83.3333 s
user5 84 s
avg_all 86.4667
above 3
below 2
s: 5
a: 
b: 
c: 

AWK函数

  1. 算术函数
  • sin()
  • cos()
  • int()
  • rand()
    ·········
srand() 更新种子
[root@bigdata tmp]# awk 'BEGIN{srand();print int(100*rand())}'
  1. 字符串函数

  2. 自定义函数

function 函数名(参数) {
	awk语句
	return awk变量
}

eg:

[root@bigdata tmp]# awk 'function double(str){return str str} BEGIN{print double("hello")}'
hellohello
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章