awk匹配反饋命令詳解

1. awk介紹

awk是一個強大的文本分析工具,相對於grep的查找,sed的編輯,awk在其對數據分析並生成報告時,顯得尤爲強大。簡單來說awk就是把文件逐行的讀入,以空格爲默認分隔符將每行切片,切開的部分再進行各種分析處理。
awk有3個不同版本: awk、nawk和gawk,未作特別說明,一般指gawk,gawk 是 AWK 的 GNU 版本。
awk其名稱得自於它的創始人 Alfred AhoPeter WeinbergerBrian Kernighan 姓氏的首個字母。實際上 AWK 的確擁有自己的語言: AWK 程序設計語言 , 三位創建者已將它正式定義爲“樣式掃描和處理語言”。它允許您創建簡短的程序,這些程序讀取輸入文件、爲數據排序、處理數據、對輸入執行計算以及生成報表,還有無數其他的功能。

2. awk原理

AWK 工作流程可分爲三個部分:

  • 讀輸入文件之前執行的代碼段(由BEGIN關鍵字標識)。
  • 主循環執行輸入文件的代碼段。
  • 讀輸入文件之後的代碼段(由END關鍵字標識)。

命令結構:

awk 'BEGIN{ commands } pattern{ commands } END{ commands }'

下面的流程圖描述出了 AWK 的工作流程:在這裏插入圖片描述

  • 1、通過關鍵字 BEGIN 執行 BEGIN 塊的內容,即 BEGIN 後花括號 {} 的內容。
  • 2、完成 BEGIN 塊的執行,開始執行body塊。
  • 3、讀入有 \n 換行符分割的記錄。
  • 4、將記錄按指定的域分隔符劃分域,填充域,$0 則表示所有域(即一行內容),11 表示第一個域,n 表示第 n 個域。
  • 5、依次執行各 BODY 塊,pattern 部分匹配該行內容成功後,纔會執行 awk-commands 的內容。
  • 6、循環讀取並執行各行直到文件結束,完成body塊執行。
  • 7、開始 END 塊執行,END 塊可以輸出最終結果。

3.實例

3.1 awk [選項] ‘{編輯指令}’ 文件

awk '{print $1,$2}' /etc/rc.local      //輸出文件的第1、2列
head -7 /etc/passwd > passwd.txt
awk -F ":" '{print $1","$7}' passwd.txt //以“:”作爲分隔符,,打印第1和7列
awk -F [:/] '{print $1,$10}' passwd.txt //以“:”或“/”作爲分隔符,,打印第1和10列
awk -F: '{print NR,NF}' passwd.txt  // 打印行數與字段數
free | awk '/Mem/{printf("RAM Usage: %.2f\n"), $3/$2*100}'| awk '{print $3}'

3.2 與管道結合

ifconfig eth0 | grep "inet" | awk '{print $2}
df -hT / | tail -1 | awk '{print $6}'
uname -a | awk '{print $1,$3,$12}'      //輸出第1、3、12字段
seq 100 | awk 'NR%7==0||NR~/7/{print}'                     #列出100以內整數中7的倍數或是含7的數
seq 100 | awk '$0%7==0||$0~/7/{print}'
行號與每行的實際文本值是一致的,那麼根據NR或者$0行值進行判斷都是可以的。輸出100以內7的倍數或是包含7的數

3.3 awk [選項] ‘[條件]{編輯指令}’ 文件

awk -F: '/bash$/{print}' passwd.txt   #以bash結尾
awk -F: '/^[a-d]/{print $1,$6}' passwd.txt   #以a-d任意字符開頭的第16列字段打印
awk -F: '/^a|nologin$/{print $1,$7}' passwd.txt  #以a開頭或nologin結尾的第17列字段打印
awk -F: '$6~/bin$/{print $1,$6}' passwd.txt    #以bin結尾的打印第16列
awk -F: '$7!~/nologin$/{print $1,$7}' passwd.txt   #輸出其中登錄Shell不以nologin結尾(對第7個字段做!~反向匹配)的用戶名、登錄Shell信息
awk -F: 'NR==3{print}' passwd.txt        #輸出第3行(行號NR等於3)的用戶記錄
awk -F: 'NR%2==1{print}' passwd.txt      #輸出奇數行(行號NR除以2餘數爲1)的用戶記錄
awk -F: 'NR<=3{print}' passwd.txt        #輸出前3行文本
awk -F: 'NR>=5{print}' passwd.txt        #輸出從第5行開始到文件末尾的所有行
awk -F: '$1=="sync"{print}' passwd.txt      #輸出用戶名爲“sync”的行
awk -F: '$1==ENVIRON["USER"]{print $1,$6,$7}' passwd.txt  #輸出當前用戶的用戶名、宿主目錄、登錄Shell信息
awk -F: 'NR>=3&&NR<=5{print}' passwd.txt
awk -F: '(NR>=3)&&(NR<=5){print}' passwd.txt
awk -F: 'NR==3||NR==5{print}' passwd.txt
awk -F: '$7!~/nologin$/||$1~/^[ad]/{print}' passwd.txt  #輸出“登錄Shell不以nologin結尾”或者“用戶名以a或d開頭”的文本
awk -F: '$3<3||$3%2==0{print}' passwd.txt    #輸出UID小於3或者UID是偶數的用戶記錄
awk -F: '$3>=501&&$3<=505{print}' /etc/passwd  #輸出UID大於501並且小於505的行
awk -F: '/^127|^192/{print}' /etc/hosts   #輸出/etc/hosts映射文件內以127或者192開頭的記錄

3.3 awk [選項] ’ BEGIN{編輯指令 } {編輯指令} END{編輯指令}’ 文件

#打印A乘於2.56的值
awk 'BEGIN{A=1024;print A*2.56}'    

#統計系統中使用bash作爲登錄Shell的用戶總個數
awk 'BEGIN{x=0}/\<bash$/{x++} END{print x}' /etc/passwd    

#輸出的內容包括三個部分:列表頭、用戶信息、列表尾
awk -F: 'BEGIN{print "User\tUID\tHome"} {print $1"\t"$3"\t"$6} END{print "Total "NR" lines."}' /etc/passwd    

#打印行數
awk -F"\t" 'BEGIN{x=0}{x+=NF}END{print x}' /etc/passwd

#以統計passwd.txt文件中以“:”分隔的總字段個數,需要每處理一行時將當前行的字段數(內置變量
awk -F: 'BEGIN{x=0}{x+=NF} END{print "Total "x" fields."}' passwd.txt   

#統計/etc/passwd文件中UID小於或等於500的用戶個數
awk -F: 'BEGIN{i=0}{if($3<=500){i++}}END{print i}' /etc/passwd   

#統計/etc/passwd文件中登錄Shell是“/bin/bash”的用戶個數
awk -F: 'BEGIN{i=0}{if($7~/bash$/){i++}}END{print i}' /etc/passwd 

#統計/etc/passwd文件中登錄Shell不是“/bin/bash”的用戶個數
awk -F: 'BEGIN{i=0}{if($7!~/bash$/){i++}}END{print i}' /etc/passwd  

#分別統計/etc/passwd文件中UID小於或等於500、UID大於500的用戶個數
awk -F: 'BEGIN{i=0;j=0}{if($3<=500){i++}else{j++}}END{print i,j}' /etc/passwd  

#分別統計/etc/passwd文件中登錄Shell是“/bin/bash”、 登錄Shell不是“/bin/bash”的用戶個數
 awk -F: 'BEGIN{i=0;j=0}{if($7~/bash$/){i++}else{j++}} END{print i,j}' /etc/passwd 

分別統計/etc/passwd文件中登錄Shell是“/bin/bash”、“/sbin/nologin”、其他的用戶個數
awk -F: 'BEGIN{i=0;j=0;k=0}{if($7~/bash$/){i++} else if($7~/nologin$/){j++}else{k++}}END{print i,j,k}' /etc/passwd
#提取IP地址及訪問量
awk  '{ip[$1]++} END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log   

#用戶登陸次數
who | awk '{IP[$1]++}END{for(i in IP){print i,IP[i]}}' 

列出黑名單)根據此可作防火牆 
awk '{IP[$1]++}END{for(i in IP){print IP[i],i}}' /var/log/httpd/access_log | awk '$1>=500{print $2}' >>ip.log

#對第1)步的結果根據訪問量排名
awk  '{ip[$1]++} END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log | sort -nr -k 2 


求最大值:
awk 'BEGIN {max = 0} {if ($1+0 > max+0) max=$1} END {print "Max=", max}' test.txt
Max= 118

求最小值:
awk 'BEGIN {min = 65536} {if ($1+0 < min+0) min=$1} END {print "Min=", min}' test.txt
Min= 9

求和:
cat test.txt|awk '{sum+=$1} END {print "Sum= ", sum}'
Sum=  236

求平均值:
cat test.txt|awk '{sum+=$1} END {print "Avg= ", sum/NR}'
Avg=  39.3333

3.4 獲取外部變量方法

3.4.1 獲得普通外部變量

語法:

awk{action}’  變量名=變量值   

這樣傳入變量,可以在action中獲得值。 注意:變量名與值放到’{action}’後面。

$ test='awk code'                           
$ echo | awk  '{print test}' test="$test"
awk code

3.4.2 BEGIN程序塊中變量

格式如:

awk –v 變量名=變量值 [–v 變量2=值2 …] 'BEGIN{action}

注意:用-v 傳入變量可以在3中類型的action 中都可以獲得到,但順序在 action前面。

[chengmo@localhost ~]$ test='awk code'                                
[chengmo@localhost ~]$ echo | awk -v test="$test" 'BEGIN{print test}'
awk code
[chengmo@localhost ~]$ echo | awk -v test="$test" '{print test}'    
awk code

3.4.3 獲得環境變量

$ awk  'BEGIN{for (i in ENVIRON) {print i"="ENVIRON[i];}}'
AWKPATH=.:/usr/share/awk
SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass
SELINUX_LEVEL_REQUESTED=
SELINUX_ROLE_REQUESTED=
LANG=en_US.UTF-8
.......

只需要調用:
awk內置變量 ENVIRON,就可以直接獲得環境變量。它是一個字典數組。環境變量名 就是它的鍵值。

4. 內建變量FS,NF,NR,RT,RS,ORS,OFS

4.1 FS 指定字段un列分隔符(Font Space)

$ echo "111|222|333" | awk '{print $1}'
111|222|333
$ echo "111|222|333" | awk 'BEGIN{FS="|"}{print $1}'
111

4.2 OFS 指定輸出字段列分隔符(Output Font space)

$ echo "111 222 333" |awk 'BEGIN{OFS="|";}{print $1,$2,$3}'
111|222|333

4.3 RS指定行分隔符 默認分隔符爲\n(Row Space)

$ echo "111 222|333 444|555 666" | awk 'BEGIN{RS="|"}{print $0}'
111 222
333 444
555 666

4.4 ORS指定輸出行分隔符

$ awk 'BEGIN{ORS="|";}{print $0;}' test.txt
111 222|333 444|555 666

4.5 RT 代指分隔符

$ echo "111 222|333 444|555 666" | awk 'BEGIN{RS="|"}{print $0,RT}'
111 222 |
333 444 |
555 666 |

4.6 NF 每行字段總數(Number of Font)

$ cat test.txt
111 222
333 444
555 666
$ awk '{print NF}' test.txt
2
2
2
$ awk '{print $NF}' test.txt
222
444
666

4.7 NR 當前行數(Number of Row)

$ cat test.txt
111 222
333 444
555 666 777
$ awk '{print NR}' test.txt
1
2
3
$ awk '{print $NR}' test.txt
111
444
777

5. awk腳本

關於awk腳本,我們需要注意兩個關鍵詞BEGIN和END。

BEGIN{ 這裏面放的是執行前的語句 }
END {這裏面放的是處理完所有的行後要執行的語句 }

{這裏面放的是處理每一行時要執行的語句}
假設有這麼一個文件(學生成績表):

$ cat score.txt
Marry   2143 78 84 77
Jack    2321 66 78 45
Tom     2122 48 77 71
Mike    2537 87 97 95
Bob     2415 40 57 62
$ cat cal.awk
#!/bin/awk -f
#運行前
BEGIN {
    math = 0
    english = 0
    computer = 0
 
    printf "NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL\n"
    printf "---------------------------------------------\n"
}
#運行中
{
    math+=$3
    english+=$4
    computer+=$5
    printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#運行後
END {
    printf "---------------------------------------------\n"
    printf "  TOTAL:%10d %8d %8d \n", math, english, computer
    printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}

我們來看一下執行結果:

$ awk -f cal.awk score.txt
NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL
---------------------------------------------
Marry  2143     78       84       77      239
Jack   2321     66       78       45      189
Tom    2122     48       77       71      196
Mike   2537     87       97       95      279
Bob    2415     40       57       62      159
---------------------------------------------
  TOTAL:       319      393      350
AVERAGE:     63.80    78.60    70.00

6. AWK 用戶自定義函數

用戶自定義函數的語法格式爲:

function function_name(argument1, argument2, ...)
{
    function body
}
  • function_name 是用戶自定義函數的名稱。函數名稱應該以字母開頭,其後可以是數字、字母或下劃線的自由組合。AWK
    保留的關鍵字不能作爲用戶自定義函數的名稱。
  • 自定義函數可以接受多個輸入參數,這些參數之間通過逗號分隔。參數並不是必須的。我們也可以定義沒有任何輸入參數的函數。
  • function body 是函數體部分,它包含 AWK 程序代碼。

求最大值與最小值

 # 返回最小值
function find_min(num1, num2)
{
  if (num1 < num2)
    return num1
  return num2
}

# 返回最大值
function find_max(num1, num2)
{
  if (num1 > num2)
    return num1
  return num2
}

# 主函數
function main(num1, num2)
{
  # 查找最小值
  result = find_min(10, 20)
  print "Minimum =", result

  # 查找最大值
  result = find_max(10, 20)
  print "Maximum =", result
}

# 腳本從這裏開始執行
BEGIN {
  main(10, 20)
}  

執行 functions.awk 文件,可以得到如下的結果:

$ awk -f functions.awk 
Minimum = 10
Maximum = 20

7. AWK 數組

AWK 可以使用關聯數組這種數據結構,索引可以是數字或字符串。

AWK關聯數 組也不需要提前聲明其大小,因爲它在運行時可以自動的增大或減小。

數組使用的語法格式:

array_name[index]=value
  • array_name:數組的名稱
  • index:數組索引
  • value:數組中元素所賦予的值

7.1 創建數組

接下來看一下如何創建數組以及如何訪問數組元素:

$ awk 'BEGIN {
sites["runoob"]="www.runoob.com";
sites["google"]="www.google.com"
print sites["runoob"] "\n" sites["google"]
}'

執行以上命令,輸出結果爲:

www.runoob.com
www.google.com

7.2 刪除數組元素

我們可以使用 delete 語句來刪除數組元素,語法格式如下:

delete array_name[index

下面的例子中,數組中的 google 元素被刪除(刪除命令沒有輸出):

$ awk 'BEGIN {
sites["runoob"]="www.runoob.com";
sites["google"]="www.google.com"
delete sites["google"];
print fruits["google"]
}'

輸出爲空。

7.3 多維數組

下面是模擬二維數組的例子:

$ awk 'BEGIN {
array["0,0"] = 100;
array["0,1"] = 200;
array["0,2"] = 300;
array["1,0"] = 400;
array["1,1"] = 500;
array["1,2"] = 600;
# 輸出數組元素
print "array[0,0] = " array["0,0"];
print "array[0,1] = " array["0,1"];
print "array[0,2] = " array["0,2"];
print "array[1,0] = " array["1,0"];
print "array[1,1] = " array["1,1"];
print "array[1,2] = " array["1,2"];
}'

執行上面的命令可以得到如下結果:

array[0,0] = 100
array[0,1] = 200
array[0,2] = 300
array[1,0] = 400
array[1,1] = 500
array[1,2] = 600
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章