awk 命令詳解 awk 是一種編程語言,用於在linux/nuix下對文本和數據進行處理。數據可以來自標準輸入、一個或多個文件,或其它命令的輸出。它支持用戶自定義函數和動態正則表達式等先進功能,是linux/unix下的一個強大的編程工具。它在命令行中使用,但更多是作為腳本來使用。 awk 的處理 ...
awk 命令詳解
awk 是一種編程語言,用於在linux/nuix下對文本和數據進行處理。數據可以來自標準輸入、一個或多個文件,或其它命令的輸出。它支持用戶自定義函數和動態正則表達式等先進功能,是linux/unix下的一個強大的編程工具。它在命令行中使用,但更多是作為腳本來使用。
awk 的處理文本和數據的方式是這樣的,它逐行掃描文件,從第一行到最後一行,尋找匹配的特定模式的行,併在這些行上進行你想要的操作。如果沒有指定處理動作,則把匹配的行顯示到標準輸出(屏幕),如果沒有指定模式,則所有被操作所指定的行都被處理。awk分別代表其作者姓氏的第一個字母。因為它的作者是三個恩,分別是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell實驗室和GNU的一些擴展。
awk命令兩種使用方式:
(1)命令行模式:awk [options] 'commands' file(s)
(2)腳本模式:awk [options] -f scriptfile file[s]
awk 命令模式
awk [options] 'commands' file(s) option: -F 定義欄位分割符號 -v 定義變數並賦值 command: 1、範圍說明或者正則表達式或者{awk命令語句1;awk命令語句2;} 2、範圍說明部分可以是BEGIN、END、邏輯表達式或者為空 3、awk命令語句間用分號間隔 4、引用shell變數時需要用雙引號引起,命令模式都在單引號''裡面 BEGIN{} {} END{} 行處理前 行處理 行處理後 命令格式: awk 'pattern' filename 示例:awk '/root/' /etc/passwd awk '{action}' filename 示例:awk -F: '{print $1}' /etc/passwd awk 'pattern {action}' filename 示例:awk -F: '/root/{print $1,$3}' /etc/passwd
示例:awk 'BEGIN{FS=":"} /root/{print $1,$3}' /etc/passwd command |awk 'pattern {action}' 示例:df -P | grep '/' |awk '$4 > 25000 {print $4}'
欄位分割及相關變數
$1,$2,$3...$n:awk中用該順序形式表示files中每行以間隔符號分割的各列的不同欄位 $0 表示文本本身 NF 表示當前記錄的欄位數(列數) $NF 最後一列 $(NF-1) 倒數第二列 FNR/NR 行號 FILENAME 文件名 "\t" 製表符 RS 換行符 "" 列印字元串 FS 定義間隔符 ~ 匹配,與==相比不是精確比較 !~ 不匹配,不精確比較 == 等於,必須全部相等,精確比較 /[0-9][0-9]+/ 兩個或兩個以上數字 -F'[:#/]' 定義三個分隔符
# awk -F: '{print $0}' /etc/passwd //列印文件所有內容 # awk -F: '{print NR, $0}' /etc/passwd /etc/hosts //列印文件所有內容,並包括行號 # awk -F: '{print FNR,$0}' /etc/passwd /etc/hosts # awk -F: '{print $0,NF}' /etc/passwd //保留記錄的欄位數 # awk 'BEGIN{FS=":"}{print $1,$3}' /etc/passwd //輸入欄位分隔符,預設為空格
格式化輸出:
print函數 # date |awk '{print "Month: "$2 "\nYear: "$NF}' # awk -F: '{print "username is: " $1 "\t uid is: "$3}' /etc/passwd # awk -F: '{print "\tusername and uid: " $1,$3 "!"}' /etc/passwd # head -5 /etc/passwd|awk -F: 'BEGIN {print "user\thomedir\tshell"RS"***********************"};{print $1"\t"$(NF-1)"\t"$NF};END {print"************END************"}
print函數 # date |awk '{print "Month: "$2 "\nYear: "$NF}' # awk -F: '{print "username is: " $1 "\t uid is: "$3}' /etc/passwd # awk -F: '{print "\tusername and uid: " $1,$3 "!"}' /etc/passwd 參數說明: %s 字元類型 %d 數值類型 占15字元 - 表示左對齊,預設是右對齊 printf預設不會在行尾自動換行,加\n
awk模式和動作
任何awk語句都由模式和動作組成。模式部分決定動作語句何時觸發及觸發事件。處理即對數據進行的操作。如果省略模式部分,動作將時刻保持執行狀態。模式可以是任何條件語句或複合語句或正則表達式。模式包括兩個特殊欄位 BEGIN和END。使用BEGIN語句設置計數和列印頭。BEGIN語句使用在任何文本瀏覽動作之前,之後文本瀏覽動作依據輸入文本開始執行。END語句用來在awk完成文本瀏覽動作後列印輸出文本總數和結尾狀態。
模式可以是:正則表達式、比較表達式、條件表達式、算術運算符、邏輯操作符和複合模式、範圍模式等。
正則表達式:
匹配記錄(整行): # awk '/^alice/' /etc/passwd # awk '!/root/' passwd 匹配欄位:匹配操作符(~ !~) # awk -F: '$1 ~ /^admin/' /etc/passwd # awk -F: '$NF !~ /nologin$/' /etc/passwd
比較表達式:
比較表達式採用對文本進行比較,只有當條件為真,才執行指定的動作。比較表達式使用關係運算符,用於比較數字與字元串。
運算符 含義 示例 < 小於 x<y <= 小於或等於 x<=y == 等於 x==y != 不等於 x!=y >= 大於等於 x>=y > 大於 x>y
# awk -F: '$3 == 0' /etc/passwd # awk -F: '$3 < 10' /etc/passwd # awk -F: '$7 == "/bin/bash"' /etc/passwd # awk -F: '$1 == "root" ' /etc/passwd # awk -F: '$1 ~ /admin/ ' /etc/passwd # df -P | grep '/' |awk '$4 > 25000'
條件表達式:
# awk -F: '$3>300 {print $0}' /etc/passwd # awk -F: '{ if($3>300) print $0 }' /etc/passwd # awk -F: '{ if($3>300) {print $0} }' /etc/passwd # awk -F: '{ if($3>300) {print $3} else{print $1} }' /etc/passwd
算術運算:+ - * / %(模) ^(冪2^3)
可以在模式中執行計算,awk都將按浮點數方式執行算術運算 # awk -F: '$3 * 10 > 500' /etc/passwd
邏輯操作符和複合模式:
&& 邏輯與 a&&b || 邏輯或 a||b ! 邏輯非 !a
# awk -F: '$3 > 50 && $3 <=100' /etc/passwd # awk -F: '$3 == 0 || $3 <=10' /etc/passwd # awk -F: '!($3 == 0 || $3 <=10)' /etc/passwd
awk 腳本編程
條件判斷:
if語句:
//格式 {if(表達式){語句;語句;...}} # awk -F: '{if($3==0) {print $1 " is administrator."}}' /etc/passwd # awk -F: '{if($3>0 && $3<1000){count++;}} END{print count}' /etc/passwd //統計系統用戶數
if...else語句:
//格式 {if(表達式){語句;語句;...}else{語句;語句;...}} # awk -F: '{if($3==0){print $1} else {print $7}}' /etc/passwd # awk -F: '{if($3==0){count++} else{i++}} END{print "管理員個數: "count ; print "系統用戶數: "i}' /etc/passwd
if...else if...else語句:
//格式 {if(表達式1){語句;語句;...}else if(表達式2){語句;語句;...}else if(表達式3){語句;語句;...}else{語句;語句;...}} # awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print i; print k; print j}' /etc/passwd # awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print "管理員個數: "i; print " 普通用個數: "k; print "系統用戶: "j}' /etc/passwd
迴圈:
while:
# awk 'BEGIN{i=1; while(i<=10){print i; i++} }' # awk -F: '{i=1; while(i<=10) {print $0; i++}}' /etc/passwd //將每行列印10次
for:
# awk 'BEGIN{for(i=1;i<=5;i++){print i} }' //C風格for awk -F: '{for(i=1;i<=10;i++) print $0}' /etc/passwd //將每行列印10次
數組:
# awk -F: '{username[++i]=$1} END{print username[1]}' /etc/passwd root # awk -F: '{username[i++]=$1} END{print username[1]}' /etc/passwd bin # awk -F: '{username[i++]=$1} END{print username[0]}' /etc/passwd root
數組遍歷:
# awk -F: '{username[x++]=$1} END{for(i=0;i<x;i++) print i,username[i]}' /etc/passwd # awk -F: '{username[++x]=$1} END{for(i=1;i<=x;i++) print i,username[i]}' /etc/passwd # awk -F: '{username[x++]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd # awk -F: '{username[++x]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd
練習
1. 統計/etc/passwd 中各種類型shell的數量 # awk -F: '{shells[$NF]++}END{ for(i in shells){print i,shells[i]}}' /etc/passwd 2. 網站訪問狀態統計 <當前時實狀態 netstat> # netstat -ant |grep :80 |awk '{access_stat[$NF]++}END{for(i in access_stat){print i, access_stat[i]}}' # netstat -ant |grep :80 |awk '{access_stat[$NF]++} END{for(i in access_stat ){print i,access_stat[i]}}' |sort -k2 -n |head # ss -an |grep :80 |awk '{access_stat[$1]++} END{for(i in access_stat){print i,access_stat[i]}}' # ss -an |grep :80 |awk '{access_stat[$1]++} END{for(i in access_stat){print i,access_stat[i]}}' |sort -k2 -rn 3. 統計當前訪問的每個IP的數量 <當前時實狀態 netstat,ss> # ss -an |grep :80 |awk -F":" '!/LISTEN/{ip_count[$(NF-1)]++} END{for(i in ip_count){print i,ip_count[i]}}' |sort -k2 -rn 4. 統計Apache/Nginx日誌中某一天的PV量 <統計日誌> # grep '07/Aug/2012' access.log |wc -l 5. 統計Apache/Nginx日誌中某一天不同IP的訪問量 <統計日誌> # grep '07/Dec/2018' access.log |awk '{ips[$1]++} END{for(i in ips){print i,ips[i]} }' |sort -k2 -rn # grep '07/Dec/2018' access.log |awk '{ips[$1]++} END{for(i in ips){print i,ips[i]} }' |awk '$2>100' |sort -k2 6. awk函數 統計用戶名為4個字元的用戶 # awk -F: '$1~/^....$/{count++; print $1} END{print "count is: " count}' /etc/passwd # awk -F: 'length($1)==4{count++; print $1} END{print "count is: "count}' /etc/passwd 7. 取得網卡IP(除ipv6以外的所有IP) # ifconfig |awk '/[ ]inet[ ]/{print $2}' 8. 獲得記憶體使用情況 # free -m |awk 'NR==2{print $3*100/$2}' 9. 獲得磁碟使用情況 # df |awk '/\/$/{print $5}' 10. 清空本機的ARP緩存 # arp |awk '!/Address/{print "arp -d " $1}'|bash # arp -n |awk '/^[0-9]/{print $1}' |xargs -I {} arp -d {}