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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章