AWK簡介
- awk是一款文本信息的統計,報告生成的工具.awk有自己的語法,是一款獨立的編程語言.
- awk支持從文本文件中讀取內容,或者從標準的輸入中讀取內容.
- awk 的最終起源於行編輯器ed,awk繼承了行編輯器的特點,循環的讀取文本的每一行(或者是分隔符分割的每一段文本)直至文本結束,但是awk加入了段分割符的概念.將每次讀入的行進行再次分割.awk每次讀取的行都只是未經過awk語句處理的對象。或讀取行後會根據段分割符在將行分成多個對象。結構近似數組,然後進行指定語句的操作
- awk 的對命令的處理可以稱爲命令的解釋,或腳本語言的解釋。 awk的語句書寫格式,屬於模塊化風格,特別是if,else語句表現的特別明顯有點類似於bash中的匿名函數。每個語句塊必須使用{}進行約束
awk的基本執行過程:
- 執行BEGIN語句塊中的內容,語句爲可選語句.多用於執行變量的初始化,報表的頭輸出.
- 從標準輸入或文件中讀取行分割符(-F定義的字符)分割的行進入內存,進行語句之前的條件匹配,在沒有條件時默認爲符合執行條件.符合條件執行,不符合條件則嘗試匹配下一個語句之前的條件.直至所有條件匹配全部完成.當語句爲空時默認執行{print $0}
- 繼續讀取下一行,直至末尾
- 執行END定義的語句內容,同樣也爲可選語句.多用於報表的統計信息輸出.
基本格式 :
awk 選項
條件
語句
文件
- 在bash命令行中執行awk時,在向awk傳入語句時,語句優先由bash優先解釋。也就是說可以向awk傳入語句時可以,bash展開傳入一些奇怪的東西,比如說系統變量,比如說{1..4}
- 選項:
-f 從文件中讀取處理命令
-F 指明行的段分隔符;分割針對輸入時的數據。支持模式匹配。擴展的正則表達式,目的是將行分割成爲多個對象.或確定每次循環時待處理的對象(最小待處理單位)是什麼.默認的
-v 自定義變量
awk -v
- 條件:
awk是一門語言,請以編程的視角去看待條件。
條件爲執行條件後的語句的要求。符合條件纔可執行語句,條件即爲對語句的判斷,可以使用正則匹配,基於正則的模式定界,字符串比較,可以使用算數條件表達式,也可以是BEGIN,END特殊條件。
算數條件表達式,最終返回運算結果,當運算結果爲0時,語句不執行。
在進行條件驗證時行已經被分割成最小的單位,並已經對最小單位的小數量,內容,行號等信息進行了統計。
- 當條件爲空時執行每一行
例:正則_匹配正則匹配的每一行
awk '/^UUID/{print $1}' /etc/fstab #匹配以UUID爲開始的行,並執行{}中的語句。print $1
awk '!/^UUID/{print $1}' /etc/fstab #匹配以非UUID爲開始的行,執行{}中的語句 。print $1
例:算數計算_條件爲真該行纔會被處理 ,條件 爲假則不處理 。
awp -F: '$3>=1000{print $1,$3}' /etc/passwd
awp -F: '!$3>=1000{print $1,$3}' /etc/passwd
awk -F: '(NR>=2&&NR<=10){print $1}'
例:字符串比較_比較結果爲真進入循環
awk -F:'$NF="/bin/bash"{print $1,$NF}' /bin/passwd
awk -F:'$NF~/bash$/{print $1,$NF}' /bin/passwd
awk -F: '! ($NF=="/bin/bash")' /etc/passwd
例:行範圍_範圍內的行做處理 ,好像只支持模式定界
awk -F:'10,20{print $1}' #----失敗了
awk -F:'/^root/,/^myuser/{print $1}'
例:特殊條件_BEGIN/END
awk 'BEGIN{print " username ID \n------------"}{printf "%10s:%-s" $1,$3}END{print "=========\n"}'
# BEGIN:在開始之前顯示一次
# END:在文本處理完成 ,命令未完成時,執行一次
例:特殊條件_0,空
awk -v aa="" 'aa' /etc/passwd #變量aa的值爲空 ,(語句爲空執行默認語句)。但是條件爲空,不執行默認語句。
awk -v aa=" " 'aa' /etc/passwd #變量aa的值爲‘ ’空格不爲空執行默認語句
awk -v aa="0" 'aa' /etc/passwd #變量aa的值爲0,條件爲最終值爲0,默認語句不執行。
awk -v aa="1" 'aa' /etc/passwd #變量aa的值爲1 ,條件返回值爲1,默認語句執行。
awk -v aa=0 'aa++' /etc/passwd #aa初始值爲0,第一條語句條件爲a++,首先返回a的值在進行自加運算。所以打印第一行外所有行。
echo "123"| awk -v a=1 'a=0{print $1}' #a的初始值爲1.第一條語句條件爲a=0,對a進行了重新賦值。此時返回a賦值後的值,條件爲0,語句不執行。
- 語句:
符合條件執行的動作,awk是一門語言,所以以編程的思維去思考。只是awk的變量大多數是awk自動賦值的。並在內部根據自己的規則自動變化(比如行計數器NR,又比如$1等)
當{}中存在多條語句時使用;進行分隔。
當語句爲空時,默認執行{print $0}
awk '!0' /etc/passwd
print :
打印 打印的類型需要進行設定
“” 定義字符串
數值直接爲數值
$爲最小元素引用
變量直接引用
在不指定打印內容時,打印整個行(我就這麼一寫)
#在沒有指定條件,以及沒有指定print輸出的內容時,默認輸出整行
例: >>echo "hello" |awk '{print}'
hello
#在指定了多個輸出內容時,對象的格式不同,使用的定義也不同
例:
echo "hello word" |awk '{print $1"\t"$2}'
hello word
echo "hello word" |awk -F' ' '{print $1"---"$2}'
hello---word
echo "hello word" |awk -F' ' '{nu=10;print $1"---"$2"---"nu}'
hello---word---10
#在沒有使用,分割字段時,默認字段是連續的,定義了輸出的字段,分割的是每個輸出的字段
例:
echo "hello word" |awk -F' ' '{print $1$2}'
helloword
echo "hello:word:haha:asd" |awk -v FS=':' -v OFS='---' '{print $1$2}'
helloword
echo "hello:word:haha:asd" |awk -v FS=':' -v OFS='---' '{print $1,$2}'
hello---word
echo "hello:word:haha:asd" |awk -v FS=':' -v OFS='---' '{print $1,$2,$1$2}'
hello---word---helloword
printf
格式化輸出字符串
格式符:
%c ascii
echo "asd"| awk '{printf "%c\n",$1}'
%d i 十進制 整數
echo "123"| awk '{printf "%-d\n",$1}'
%e %E 科學記數法
%f 顯示 浮點數
%s 顯示 字符串
echo "123"| awk '{printf "%s\n",$1}'
123
echo "123"| awk '{printf "%s\n","asd"}'
asd
%% 顯示%自身
%g %G 以科學技術法顯示
%u 無符號的 整數
修飾符 :
# 顯示寬度
#。#;第二個 # 表示 小數點 後的精度
- : 左對齊,默認右對齊。
+ :顯示數字的正負符號
條件表達式:
格式:條件?條件爲真的語句:條件爲假的語句
awk ‘{$3>=1000?usertype="......":usertype="::::::";printf "%15s:%-s\n",$1,usertype}’
控制語句:
if:
格式:
if(條件){語句}
if(條件){語句} else {語句}
例:
awk -F: '{if($3>1000) print $1,$3}' /etc/passwd #打印非系統用戶
awk -F: '{if($3>1000){printf "普通用戶:%s",$1} else {printf "系統用戶:%s",$1}}' #對系統的用戶進行判斷,輸出結果。
df -h |awk -F% '/\/dev\/sd/{print $1}'|awk '{if($NF>=16)print $1}'
df -h |awk -F% '/\/dev\/sd/{print $1}'|awk '$NF>=16{print $1}'
循環語句:
while:
while (條件) {語句}
條件爲真進入循環 ,條件爲假退出循環。
awk '/^[[:space:]]*linux/{i=1;while(i<NF){print $i,length($i);i++}}' /etc/grub2.cfg
awk '/^[[:space:]]*linux/{i=1;while(i<NF){if(length($i)>7){print $i,length($i)};i++}}' /etc/grub2.cfg
awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=10){print $i,length($i)}; i++}}' /etc/grub2.cfg
do:
do{語句} while(條件)
首先執行do後面的語句。然後對while中的條件進行判斷。條件符合繼續執行do後的語句。
awk 'BEGIN{total=0;i=0;do{total+=i;i++;}while(i<=100);print total}'
awk 'BEGIN{total=0;i=0;while(i<=100){total+=i;i++};print total}'
for:
for (i=1;i<10;i++){語句}
awk /[[:space:]]*linux/{for(i=1;i<=NF;i++){print $i,length($i)}} /etc/grub2.cfg
for可以實現遍歷數組元素 :
格式 :for (i in 數組名稱)遍歷時 i被賦值的是每個索引,
switch
循環跳轉
break
跳出當前循環,break # :跳出#層循環
contiune
結束本次次循環, continue # :結束啊 #層的本次循環。
next :結束 當前行的處理,讀取下一行。gawk 的自帶循環 ,結束行的處理,進入下一行
awk -F: '{if($3%2!=0) next;print $0 }' /etc/passwd
打印奇數行
delete
exit
函數:
內置函數
lrngth
統計指定字符串的長度,並返回。
例: echo "asdd"|awk '{print length($1)}' #統計字符串出現的次數。
rand,srand
rand,與srand 組合使用返回一個隨機數
例: awk 'BEGIN{srand();for(i=1;i<=10;i++){print int(rand()*100)}}'
sub
格式sub(r,s,[t])
處理字符串t(可以是單純的字符串,變量,位置引用),對t進行模式匹配,模式定義在r中,將模式r所匹配的內容替換成s中的內容,但是隻進行1次替換
例: echo "2008:08:08:08 08:08:08:08" |awk 'sub(/:/,"-",$0)'
gsub
格式 gsub (r,s,[t])
處理字符串t(可以是單純的字符串,變量,位置引用),對t進行模式匹配,模式定義在r中,將模式r所匹配的內容替換成s中的內容,對於待處理的字符串t進行全局替換。
例: echo "Yd$C@M05MB%9&Bdh7dq+YVixp3vpw"|awk '{gsub(/[^0-9]/,"",$0);print $0}'
echo "Yd$C@M05MB%9&Bdh7dq+YVixp3vpw"|awk 'gsub(/[^0-9]/,"",$0)'
split
格式 split(a,array,[r])
以r爲分隔符,分割字符串a,並將分割後的字符串分別存入數組,數組的下標從1開始,第一個索引爲1,第二個索引爲2.
netstat -tan |awk '/^tcp/{split($4,ip,":");a[ip[1]]++}END{for(i in a){print i,a[ip[1]]}}'
int
格式 int(需要轉換的小數,或字符串)
將指定的內容轉換爲整數類型。
system
格式: system("系統命令")
將傳入的字符串以系統命令方式執行。命令先經過bash解釋傳入,所有傳入時到awk解釋時,必須保證是需求的字符,在經過awk解釋時,必須符合awk的語法。也就是保證經bash解釋後成爲符合awk語法格式切符合需求的字符。或者確保傳入的函數的值,爲需要的值。
例:awk 'BEGIN{system("hostname")}'
awk 'system("hostname"){i=0}'
自定義函數
格式:
function 函數名稱 (參數1 ,參數2 。。。){
語句1
語句2
return 數值
}
將語句與函數定義在文件中,使用awk運行。
#cat fun.awk
function max(v1,v2) {
v1>v2?var=v1:var=v2
return var
}
BEGIN{a=3;b=2;print max(a,b)}
#awk –f fun.awk
將語句與函數定義在腳本中,使用shebang,直接運行腳本。
將awk程序寫成腳本,直接調用或執行
#cat f1.awk
{if($3>=1000)print $1,$3}
#awk -F: -f f1.awk /etc/passwd
#cat f2.awk
#!/bin/awk –f
#this is a awk script
{if($3>=1000)print $1,$3}
#chmod +x f2.awk
#f2.awk –F: /etc/passwd
awk腳本中傳遞參數:
格式:
awkfile var=value var2=value2... Inputfile
注意:在BEGIN過程中不可用。直到首行輸入完成以後,變
量纔可用。可以通過-v 參數,讓awk在執行BEGIN之前得到
變量的值。命令行中每一個指定的變量都需要一個-v參數
#cat test.awk
#!/bin/awk –f
{if($3 >=min && $3<=max)print $1,$3}
#chmod +x test.awk
#test.awk -F: min=100 max=200 /etc/passwd
數據引用:
行的分段引用
每個分段之間使用,進行分割,當不使用,進行分割時默認爲一個字段,
$1 :該行的第一個元素
$2 :該行的第一個元素
換行符有必要寫一下,換個行而已沒什麼神聖的,解釋了是換行不解釋就是\n,awk,看到的文本是連續的,或者說是一串,只是到了換行被截斷。
變量:
內建的變量。
內建變量的賦值 -v FS=" " 每一個-v用來定義一個變量,
FS:輸入的字段分割符,默認爲空白字符
OFS:輸出的字段分隔符,默認也爲空白字符。
RS:輸入時指明的行分割符,默認就是換行符,
ORS:輸出時的行分隔符,默認爲換行符
NF :行中的字段數量
NR :行計數器 ,如果跟了多個 文件 ,編號會連續
FNR : 基於文件的 行計數器 。
FILENAME : 當前的文件名
ARGC :命令行中的參數個數
ARGV :命令行中的參數 ,ARGV爲數組,參數爲命令自身及後跟隨的文件 ,語句不計入參數
自定義的變量
-v var=value
在 與語句中 直接 定義
多條與語句之間 使用 ;分隔
操作符
算數操作符 :
雙目運算符 :
x+y x-y x*y x/y x^y x%y
單目運算符 :
-x :將x 轉化爲負數
+x :將字符串x 轉化爲 數值
字符串的 操作符 :連接符什麼 鬼
賦值操作符 :
+ += -= *= /= ^= %=
++ --
> >= < <= != ==
模式匹配:
~ : 是否匹配
!~: 是否 不匹配
邏輯操作符 :
&& || !
函數調用 :
函數名(參數 ,參數 )
數組:
awk的數組爲關聯數組,就是Python中的字典。
數組索引可以使用任意的字符串索引,字符串使用引號
如果某數組元素不存在,引用時會創建初始值爲none,在進行數學運算時 none會自動轉化爲0進行計算。
數組賦值
array[\$1]=aa
array[\$1]++
awk '!arr[\$0]++' /etc/fstab
排除重複的行,取出第一行是對應的數組的內容爲空,將none返回然後進行自加後值爲1,返回的值經過!取反爲真執行默認語句,同樣的語句第二次出現時,返回的值爲1,經過!取反,值爲假,反而不執行.
awk '{arr[$0]++;print $0,arr[$0]}'
打印並統計重複行出現的次數.
遍歷數組
netstat -tan | awk '/tcp\>/{stat{$NF}++}END{for(i in stat){print i,stat[i]}}