一、awk簡介
awk是一個非常好用的數據處理工具,相對於sed常常作用於一整個行的處理,awk則比較傾向於一行當中分成數個【字段】處理,因此,awk相當適合處理小型的數據數據處理。awk是一種報表生成器,就是對文件進行格式化處理的,這里的格式化不是文件系統的格式化,而是對文件內容進行各種“排版”,進而格式化顯示;在linux中我們使用的是GNU awk簡稱gawk,並且gawk其實就是awk的鏈接文件,因此在系統上使用awk和gawk是一樣的。
二、awk語法
語法格式:
awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file[,file2,...,filen]
選項:
[-F|-f|-v] 大參數,-F指定分隔符,-f調用腳本,-v定義變量 var=value
' ' 引用代碼塊
BEGIN 這里面放的是執行前的語句。初始化代碼塊,主要是引用全局變量,設置FS分隔符。
// 匹配代碼塊,可以是字符串或正則表達式
{} 這里面放的是處理每一行時要執行的語句。命令代碼塊,包含一條或多條命令,多條命令使用分號分隔
END 這里面放的是處理完所有的行后要執行的語句。結尾代碼塊,主要是進行最終計算或輸出結尾摘要信息
舉例:
cat ceshi.txt |awk -v FS: '{print $1,$3}'(每行按冒號分割,輸出第一個域和第三個域;默認為空格分割;注意:awk后續動作都要以單引號引起來)
cat ceshi.txt |awk -v FS: '{print $1"XXXX"$3}'("XXXX"代表任意內容,必須用雙引號引起來)
三、變量
1、內建變量
FS 輸入字段分隔符,默認為空格
RS 輸入的記錄分隔符,默認為換行符(即文本是按一行一行輸入)
OFS 輸出字段分割符,默認為空格
ORS 輸出的記錄分隔符,默認為換行符(即處理結果也是一行一行輸出到屏幕)
NF 當前行的字段的數量
print NF 顯示當前行的字段數
print $NF 顯示當前行的第NF字段的值
$0 表示整個當前行
$1 每行第一個字段
NR 每行的記錄號,多文件記錄遞增
FNR 每個文件分別計數,顯示行號。與NR類似,不過多文件記錄不遞增,每個文件都從1開始
FILENAME 當前文件名
ARGC 命令行參數的個數
ARGV 保存命令行所給定的各參數的數組
\t 制表符
\n 換行符
~ 匹配,與==相比不是精確比較
!~ 不匹配,不精確比較
== 等於,必須全部相等,精確比較
!= 不等於,精確比較
&& 邏輯與
|| 邏輯或
+ 匹配時表示1個或1個以上
/[0-9][0-9]+/ 兩個或兩個以上數字
/[0-9][0-9]*/ 一個或一個以上數字
2、自定義變量
(1)-v VALUE(變量名稱區分大小寫)在這里文件ceshi.txt中有多少行就顯示多少行變量的值
awk -v fan="cool" '{print fan}' ceshi.txt
(2)在代碼塊中自定義變量
awk 'BEGIN{FS=":";abc=1}{print $abc}' ceshi.txt
四、awk的輸出
1、print & $0
print 是awk打印指定內容的主要命令
舉例:
awk '{print}' /etc/passwd == awk '{print $0}' /etc/passwd
awk '{print " "}' /etc/passwd //不輸出passwd的內容,而是輸出相同個數的空行,進一步解釋了awk是一行一行處理文本
awk '{print "a"}' /etc/passwd //輸出相同個數的a行,一行只有一個a字母
awk -F":" '{print $1}' /etc/passwd
awk -F: '{print $1; print $2}' /etc/passwd //將每一行的前二個字段,分行輸出,進一步理解一行一行處理文本
awk -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd //輸出字段1,3,6,以制表符作為分隔符
2、格式化輸出printf
語法 printf FORNAT,item1,item2
FORMAT必須提供;與print語句不同,printf不會自動換行,需要使用換行符\n
FORMAT中需要分別為后面的每個item指定一個格式符,否則item無法顯示;
格式符介紹:
%c 顯示字符的ASCII碼
%d,%i 顯示為十進制整數
%e,%E 科學技術法顯示數值
%f 顯示為浮點數
%g,%G 以科學技術法或浮點數格式顯示數值
%s 顯示為字符串
%u 顯示無符號整數
%% 當需要顯示%號時需要連續打兩個百分號
舉例說明:
cat ceshi.txt |awk -F: '{printf "%-10s%s\n",$1,$3}'
五、awk的操作符
算術操作符 如:A+B A-B A*B A/B
字符操作符 字符串鏈接
賦值操作符 如:-= += /= %=
比較操作符 如:> >= < <= ==
模式匹配操作符 ~ 是否能由右側指定的模式所匹配 !~是否不能由右側指定的模式所匹配
邏輯操作符 && 與運算 || 或運算
條件表達式 selector?if-true-expression:if-ials-expreion
函數調用 調用函數來進行數據的處理
舉例:
通過df命令查看當前系統磁盤占用率,查出占用率大於等於百分之20的磁盤名稱以及磁盤占用率
df|awk -v FS=% '$0 ~ "/dev/sd" {print $1}'|awk '$NF>=20 {printf "DevName:%-10s Used:%s%%\n",$1,$5}'
awk -v FS=: '{$3>=5?usertype="Big User":usertype="Small User";printf "UserName:%-15s Type:%s\n",$1,usertype}' ceshi.txt
六、awk的控制語句
參考博客:https://www.cnblogs.com/pigdragon/p/6473850.html
1、if語句
語法:if(condition){statements}[else {statement}]
舉例:awk -F: '{if($3>=5){printf "%-10s%s\n",$1,$3}}' ceshi.txt
2、while語句
語法:while(condition){statements}
舉例:echo {1..10} |awk '{n=1;while(n<=NF){if($n%2==0){print $n,"oushuo"}else {print $n,"jishu"};n++}}'
3、do-while語句
語法:do {statements} while (condition)
舉例:echo {1..10} |awk '{n=1;do{if($n%2==0){print $n,"oushuo"}else {print $n,"jishu"};n++}while(n<=NF)}'
4、for語句
for循環有兩種格式:
格式1:for(變量 in 數組){語句}
舉例:awk 'BEGIN{ for(k in ENVIRON) {print k"="ENVIRON[k]; } }'
格式2:`for(變量;條件;表達式){語句}`
舉例:`awk 'BEGIN{ total=0; for(i=0;i<=100;i++) {total+=i; } print total; }'`
5、退出循環
(1)break
(2)continue
(3)delete array
(4)exit
(5)next 提前結束對本行文本的處理,而提前進入下一行的處理操作
舉例:
awk -F: '{if($3%2==0)next;print $1,$3}' ceshi.txt
七、awk的性能測試
實驗:從1加到100等於多少?
(1)time (awk 'BEGIN{ total=0;for(i=0;i<=10000;i++){total+=i;}print total;}')
50005000
real 0m0.003s
user 0m0.003s
sys 0m0.000s
(2)time(total=0;for i in $(seq 10000);do total=$(($total+i));done;echo $total;)
50005000
real 0m0.141s
user 0m0.125s
sys 0m0.008s
實現相同功能,可以看到awk實現的性能是shell的50倍!
八、awk數組
數組是一個包含一系列元素的表
格式如下:
abc[1]="libai"
abc[2]="lihei"
abc為數組名,[1][2]為數組下標,可以認為是數組的第一個元素,第二個元素,"libai""lihei"是元素的內容
舉例說明:
awk 'BEGIN{fan[0]="libai";fan[1]="lihei";print fan[0]}'
awk 'BEGIN{fan[0]="libai";fan[1]="lihei";print fan[1]}'
awk 'BEGIN{fan[0]="libai";fan[1]="lihei";for (i in fan)print i}'
awk -F: '{{fan[NR]=$1;}{print NR,fan[NR]}}' ceshi.txt
利用數組統計每個ip地址訪問量(編輯一個文件,該文件存儲ip地址)
awk '{array[$1]++} END {for(key in array) print array[key],key}' a|sort -r
關於array[$1]++
(1)awk在讀取第一行的時候,會讀取這個數組,此時的數組是這樣的,array["第一行的內容"]++
(2)此時該數組的值還沒有定義,但后面有運算符號++,所以awk會將數字0自動賦值給array["第一行的值"]做++運算,所以得到的值為1.
(3)在讀到與array["第一行的內容"]相同的時候繼續++運算,也就意味着,運算了多少次,就是出現了多少次。
九、awk函數
1、內鍵函數
(1)數值處理 rand() 返回0至1之間的一個隨機數
awk 'BEGIN{print rand()}'
通過使用rand函數生成隨機數,返回的值一直不變,所以我們需要配合srand函數
awk 'BEGIN{srand();print rand()}'
生成的隨機數產生了變化,但生成的隨機數都是小於1的小數,如果我們想要生成整數隨機數,我們可以利用int整數函數截取整數部分的值
awk 'BEGIN{srand();print 100*rand()}'
awk 'BEGIN{srand();print int(100*rand())}'
(2)字符串函數
length([s]) 返回指定的字符串的長度
舉例說明:
awk '{print $0 length()}' abc.txt (每一行全部字符長度)
awk '{for(i=1;i<=NF;i++){print $i,length($i)}}' abc.txt(指定字符長度)
gsub(r,s[,t])基於r所表示的模式來匹配字符串t中的內容,將其所有被匹配到的內容均替換為s所表示的字符串
舉例說明:
awk '{gsub("h","H",$1);print $0}' abc.txt
awk '{gsub("h","H",$0);print $0}' abc.txt
sub(r,s[,t]) 基於r所表示的模式來匹配字符串t中的內容,將其第一次被匹配到的內容替換為s所表示的字符串
舉例說明:
awk '{sub("h","H");print $0}' abc.txt(只替換指定范圍第一次匹配到的符合條件的字符)
split(s,a[,r]) 以r為分隔符去切割字符串s,並將切割后的結果保存至a表示的數組中
舉例說明:
awk -v aa="李大;李二;李三" 'BEGIN{split(aa,lishijiazu,";");for(i in lishijiazu){print lishijiazu[i]}}'
awk -v aa="cc;ff;dd;ee" 'BEGIN{split(aa,lishijiazu,";");for(i in lishijiazu){print lishijiazu[i]}}'
從上面我們發現數組元素輸出順序可能與字符串中字符的順序不同,我們可以采用下面的辦法
awk -v aa="cc;ff;dd;ee" 'BEGIN{ abc=split(aa,lishijiazu,";");for(i=1;i<=abc;i++){print i,lishijiazu[i]}}'
2、用戶自定義函數
函數是程序的基本組成部分,awk允許我們定義自己的函數,一個大的程序可以分為多個函數並且每個函數可以獨立測試
用戶自定義函數的一般格式為:
function function_name(argument1,argument2,...)
{
function body
}
function_name是用戶定義函數的名稱,函數名稱應以字符的字母並且其余部分可以是數字,字母或下划線的任意組合,awk的保留字不能用作函數名字;函數可以接受以逗號分隔的多個參數,參數不是強制性的,我們也可以創建一個用戶定義的函數不帶任何參數;函數體由一個或多個awk語句組成。
參考博客:
[1]linux awk命令詳解
[2]linux中awk 詳解
