Linux文本處理工具三劍客:grep、sed和AWK。其中grep是一種文本過濾工具,sed是文本行編輯器,而AWK是一種報表生成器,就是對文件進行格式化處理,這裏的格式化不是文件系統的格式化,而是對文件內容進行各類「排版」,進而格式化顯示
在Linux之上咱們使用的GUN awk ,簡稱gawk,而且gawk其實awk的連接文件,所以在系統上使用awk和gawk都是同樣的。咱們經過mangawk能夠得到gawk的相關功能說明----------- gawk-pattern scanning and processing language(模式掃描及各類處理語言),gawk是一種過程式編程語言,gawk還支持條件判斷,數組、循環等各類編程語言中全部可使用的功能,所以咱們還能夠吧gawk稱爲一種監本語言解釋器。linux
awk 在處理文本時也是一次讀取一行文本,文件的每一行稱爲記錄,由分隔符分隔的字段(域)標記爲$1,$2...$n,稱爲域標識,$0爲全部域,和shell中變量$符含義不一樣,而後根據輸入分隔符(默認爲空格字符)進行切片,切成n段,而後將每一片都賦予awk內部的一個變量當中這些$1,$2等等一直到最後一個,awk就能夠對這些片斷進行處理,好比某一段、特定段,好比計數、運算等正則表達式
#awkshell
# awk -f /PATH/AWK_SCRIPTexpress
#!/bin/awk -f編程
awk [option] ‘program’ file1 file2
Option:選項
-F[] :指明輸入時用到的字段分隔符,例:-F:
-v var=value: 自定義變量,例:-v var=123
-f /PATH/AWK_SCRIPT:指定awk程序的文件
Program:prattern{action statements;}
awk編程語言,一般由BEGIN語句塊、可以使用模式匹配的通用語句塊、END,共3部分組成。Program一般是被單引號或雙引號中
parttern部分決定動做語句什麼時候觸發及觸發事件
BEGIN:在讀取文件以前執行
END:在讀取文件以後執行
Action statements:動做語句,能夠是由多個語句組成,各語句之間使用分號分隔「;」
print:換行打印
printf:不換行打印 數組
第一步:執行BEGIN{action;… }語句塊中的語句
第二步:從文件或標準輸入(stdin)讀取一行,而後執行pattern{ action;… }語句塊,它逐行掃描文件,從第一行到最後一行重複這 個過程,直到文件所有被讀取完畢。
第三步:當讀至輸入流末尾時,執行END{action;…}語句塊
BEGIN語句塊在awk開始從輸入流中讀取行以前被執行,這是一個 可選的語句塊,好比變量初始化、打印輸出表格的表頭等語句一般 能夠寫在BEGIN語句塊中
END語句塊在awk從輸入流中讀取完全部的行以後即被執行,好比 打印全部行的分析結果這類信息彙總都是在END語句塊中完成,它 也是一個可選語句塊
pattern語句塊中的通用命令是最重要的部分,也是可選的。若是 沒有提供pattern語句塊,則默認執行{ print },即打印每個讀取 到的行,awk讀取的每一行都會執行該語句塊bash
變量:內置變量和自定義變量tcp
FS:輸入字段分隔符,默認爲空白字符
awk -v FS=':' '{print $1,FS,$3}’ /etc/passwd
awk –F: '{print $1,$3,$7}’ /etc/passwd
OFS:輸出字段分隔符,默認爲空白字符
awk -v FS=‘:’ -v OFS=‘:’ '{print $1,$3,$7}’ /etc/passwd
RS:輸入記錄分隔符,指定輸入時的換行符,原換行符仍有效
awk -v RS=' ' ‘{print }’ /etc/passwd
ORS:輸出時的行分隔符,默認爲換行符
awk -v RS=' ' -v ORS='###'‘{print }’ /etc/passwd
NF:字段數量,當前行的字段數
awk -F: ‘{print NF}’ /etc/fstab,顯示當前行的字段數
awk -F: '{print $(NF-1)}' /etc/passwd 顯示當前行的第NF個字段
NR:顯示行數;命令後跟的全部文件將統一合併計數
awk '{print NR}' /etc/fstab
awk END'{print NR}' /etc/fstab
FNR:顯示行號;各文件分別計數,行號
awk '{print FNR}' /etc/fstab /etc/inittab
FILENAME:顯示當前文件名
awk '{print FILENAME}’ /etc/fstab
ARGC:命令行參數的個數
awk '{print ARGC}’ /etc/fstab /etc/inittab
awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab
ARGV:數組,保存的是命令行所給定的各參數
awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab
awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab
注意:當引用這些內置變量時,不用加$;使用ARGC和ARGV時,後面能夠是文件名,也能夠是a b c d 任意值,不論是文件名或是任意字符串,以空格相隔,每個值都會被賦值給ARGC這個數組的不一樣下標,默認從0開始,awk也是一個參數,awk是固定的被賦值給了ARGV[0],後面的全部參數按順序分配給各個下標,
例:1.這個命令便是打印出這個參數的個數,加上awk自己總共5個
2.顯示各個參數的值
編程語言
自定義變量是區分字符大小寫的,自定義變量有兩種方法:編輯器
例: awk -v test='hello gawk' '{print test}' /etc/fstab
awk -v test='hello gawk' 'BEGIN{print test}'
awk 'BEGIN{test="hello,gawk";print test}'
awk –F:‘{sex=「male」;print $1,sex,age;age=18}’ /etc/passwd
用-v選項和在program中定義的變量的區別,使用-v定義的變量,只有第一次執行的時候會讀取一次,在後面的program中弱勢變量值發生變化,便不可再回到初值,而program中的命令是每讀取一行的時候就會被執行一次,因此,當每讀取完一行的時候都會再次被賦值爲最初的那個值,因此能夠根據本身的需求來選擇怎麼定義變量,在調用這些變量的值的時候不須要加$,因此若是要輸出一些字符串的時候,須要用上引號引發來,不然系統則會認爲是要調用變量名爲這串字符串的變量的值,
print格式 print item1,item2...
awk '{print "hello world"}' 顯示字符串hello world
awk -F: '{print}' /etc/passwd 顯示/etc/passwd文件中的全部內容
awk -F: '{print "wang"}' /etc/passwd 每讀取/etc/passwd文件中一行內容輸出一次字符串「wang」
awk -F: '{print $1}' /etc/passwd 每讀取一行,就截取以「:」爲分隔符的第一個字段
awk -F: '{print $0}' /etc/passwd 顯示/etc/passwd文件中每一行以「:」分隔的全部字段(等同於awk -F: '{print}' /etc/passwd)
awk -F: '{print$1"\t"$3}' /etc/passwd 輸出/etc/passwd每行第1和第3字段,中間以tab分隔
tail -3 /etc/fatab |awk’{print $1,$4}’ 顯示/etc/fstab中最後3行的第1字段和第4字段
printf 「FORMAT」 ,item1,item2...
輸出格式符(FORMAT):與item一一對應
%c: 顯示字符的ASCII碼
%d, %i: 顯示十進制整數
%e, %E:顯示科學計數法數值
%f:顯示爲浮點數
%g, %G:以科學計數法或浮點形式顯示數值
%s:顯示字符串
%u:無符號整數
%%: 顯示%自身
修飾符:每一種格式符都有一些修飾符
#[.#]:第一個數字控制顯示的寬度;第二個#表示小數點後精度,%3.1f
-: 左對齊(默認右對齊) %-15s
+:顯示數值的正負符號 %+d
示例:
awk -F: ‘{printf "%s",$1}’ /etc/passwd
awk -F: ‘{printf "%s\n",$1}’ /etc/passwd
awk -F: ‘{printf "%-20s %10d\n",$1,$3}' /etc/passwd
awk -F: ‘{printf "Username: %s\n",$1}’ /etc/passwd
awk -F: ‘{printf 「Username: %s,UID:%d\n",$1,$3}’ /etc/passwd
awk -F: ‘{printf "Username: %15s,UID:%d\n",$1,$3}’ /etc/passwd
awk -F: ‘{printf "Username: %-15s,UID:%d\n",$1,$3}’ /etc/passwd
算數操做符:
x+y:加;
x-y:減;
x*y:乘;
x/y:除;
x^y:次方;
x%y:取餘;x除以y得出的餘數
-x:轉換爲負值,
+x轉換爲數值
字符串操做符:沒有符號的操做符,字符串鏈接
賦值操做符:
=:等於;
+=:自加;例,x+=y,意思是把x自己的值加上y的值再賦給x
-=: 自減;例,x-=y,意思是把x減去y的值再賦值給x
*=: 自乘;例,x*=y,意思是把x乘以y的值再賦值給x
/=: 自除;例,x/=y,意思是把x除以y的值再賦值給x
%=:取餘賦值;例,x%=y,意思是x除以y後的餘數賦值給x
^=: 次方;例,x^=y,意思是把x的y次方的值再賦值給x
++:遞加;例,i++,意思是把i的值加1再賦值給i,等同於i+=1
- -: 遞減;例,i- -,意思是把i的值減1再賦值給i,等同於i-=1
比較操做符:
= =: 等於
!=: 不等於
\>: 大於
\>=: 大於等於
<: 小於
<= : 小於等於
模式匹配符:
~:左邊是否匹配包含右邊
!~: 是否左邊和右邊是否不匹配包含
邏輯操做符:與&&;或||;非!
示例:
awk –F: '$0 ~ /root/{print $1}‘ /etc/passwd
awk '$0~「^root"' /etc/passwd
awk '$0 !~ /root/‘ /etc/passwd
awk –F: ‘$3==0’ /etc/passwd
awk –F: '$3\>=0 && $3\<=1000 {print $1}' /etc/passwd
awk -F: '$3==0 || $3\>=1000 {print $1}' /etc/passwd
awk -F: ‘!($3==0) {print $1}' /etc/passwd
awk -F: ‘!($3\>=500) {print $3}’ /etc/passwd
函數調用:function_name(argu1,argu2...)
條件表達式(三目表達式):
格式: selector?if-true-expression:if-false-expression
三目表達式顧名思義就是有三個表達式組成的,問號以前的表達式一般爲判斷表達式,問號以後的表達式是知足條件纔會執行的語句,冒號以後的是當不知足條件時纔會執行的語句。
示例:
awk -F: '{$3>=1000?usertype="common user":usertype="sysadmin or sysuser";printf "%15s: %-s\n" ,$1,usertype}' /etc/passwd
PATTERN:根據pattern條件,過濾匹配的行,再作處理
awk '/^UUID/{print $1}' /etc/fstab
awk '!/^UUID/{print $1}' /etc/fstab
真:結果爲非0值,非空字符串
假:結果爲空字符串或0值
示例:
awk -F: 'i=1;j=1{print i,j}' /etc/passwd
awk ‘!0’ /etc/passwd
awk ‘!1’ /etc/passwd
awk –F: '$3\>=1000{print $1,$3}' /etc/passwd
awk -F: '$3\<1000{print $1,$3}' /etc/passwd
awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
awk -F: '$NF ~ /bash$/{print $1,$NF}' /etc/passwd
Startline,endline:/pat1/,/pat2/不支持直接給出數字格式
示例:
awk -F: '/^\<root\>./,/^\<nobody\>./{print $0}' /etc/passwd
awk -F: '/^\<root\>/,/^\<nobody\>/{print $0}' /etc/passwd
awk -F: '(NR>=10&&NR<=20){print NR,$1}' /etc/passwd
BEGIN{}:僅在開始處理文件中的文本以前執行一次
END{}:僅在文本處理完成以後執行一次
awk -F : 'BEGIN {print "USER USERID"} {print $1":"$3} END{print "end file"}' /etc/passwd
awk -F : '{print "USER USERID「;print $1":"$3} END{print "end file"}' /etc/passwd
awk -F: 'BEGIN{print " USER UID \n--------------- "}{print $1,$3}' /etc/passwd
awk -F: 'BEGIN{print " USER UID \n--------------- "}{print $1,$3}'END{print "=============="} /etc/passwd
seq 10 |awk ‘i=0’ 不顯示全部行
seq 10 |awk ‘i=1’ 顯示全部行
seq 10 | awk 'i=!i‘ 顯示基數行
seq 10 |awk -v i=1 '!(i=!i)' 顯示基數行
seq 10 | awk '{i=!i;print i}‘每執行一行,顯示一次i的真假值
seq 10 | awk ‘!(i=!i)’ 顯示偶數行
seq 10 |awk -v i=1 'i=!i' 顯示偶數行
語法:if(condition){statement1}[else{statement2}]
If(condition1){statement}else if(condition2){statement2}else{statement3}
這種語法看着跟shell中的if--else語句相差無幾,第一種格式是單if語句,執行機制是先判斷條件(condition)部分,值爲則true執行statement1部分語句,值爲false則執行statement2部分的語句;第二種是多if語句,有多個條件多個語句,先判斷第一個條件(condition1),值爲true執行statement1部分的語句,值爲false就判斷下一個條件condition2,值爲true就執行statement2,值爲false就執行else後面的statement3語句;
使用場景:對awk取得的整行或某個字段作條件判斷
示例:
awk -F: '{if($3>=1000)print $1,$3}' /etc/passwd
awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
awk '{if(NF\>5) print $0}' /etc/fstab
awk -F: '{if($3\>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd
awk -F: '{if($3\>=1000) printf "Common user: %s\n",$1; else printf "root or Sysuser: %s\n",$1}' /etc/passwd
df -h|awk -F% '/^\/dev/{print $1}'|awk '$NF\>=80{print $1,$5}‘
awk 'BEGIN{ test=100;if(test\>90){print "very good"} else if(test\>60){ print "good"}else{print "no pass"}}'
語法:while(condition){statement;...}
執行機制:先判斷再執行,條件真,進入循環;條件假退出循環,statement部分能夠有多個語句,組合語句,在statement處應該有一條是條件判斷的值發生變化的語句,不然容易進入死循環
使用場景:對一行內的多個字段逐一相似處理時使用;對數組中的各元素逐一處理時使用
示例:
awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {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{statement;}while(condition)
執行機制:先執行再判斷,先執行一遍statement,再判斷condition,若是條件爲真則進入下一輪循環,若是爲假就退出,不管真假,至少執行一次循環體
示例:
awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}‘
思考:下面兩語句有何不一樣?
awk ‘BEGIN{i=0;print ++i,i}’
awk ‘BEGIN{i=0;print i++,i}’
前者輸出的++i是先給i加1在輸出,後者是先輸出i再給i加值
語法:for (expr1;expr2;expr3){statement;...}
常見用法:for(var assignment;condition;iteration process){for-body}
執行機制:variable assignment(變量的初始值),condition(條件),iteration process(步長,也就是沒執行一次循環體後,使變量的值發生變化的語句);for-body(循環體),先賦初值變量(variable),再判斷變量的值是否符合條件(condition),符合就執行循環體部分(for-body),而後再給變量加上步長(iteration process),再判斷條件,爲真時執行循環體部分,爲假退出循環......
特殊用法:for(var in array) {for-body}
執行機制:給var多個值,一次使用一個值,執行一次循環,有多少個值就執行多少次循環,直到把array的全部的值都用完,array表明一個數組。
示例:
awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
性能比較就是,看某個命令從執行到出結果時的時長,哪一個時間最短就說明哪一個命令性能更好,這個查看性能的命令就是time,在命令的前面寫入time,把要執行的命令用小括號括起來,再執行此命令,就會在顯示執行結果的後面顯示出時間
例:
time(awk'BEGIN{ total=0;for(i=0;i<=10000;i++){total+=i;};print total;}')
time(total=0;for i in {1..10000};do total=$(($total+i));done;echo $total)
time(for ((i=0;i<=10000;i++));do let total+=i;done;echo $total)
time(seq –s 」+」 10000|bc)
語法:switch(expression) {case VALUE1 or /REGEXP1/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}
執行機制:這個就至關於shell中的case語句,espression是一個表達式,當VALUE1的值知足REGEXP1的時候執行statement1,當VALUE2的值知足REGEXP2的時候,執行statement2語句,...當前面的全部條件都不知足的時候,執行default後面的statement n語句。
這兩個語句的用法continue是提早結束當前這一輪循環,進入下一循環,break是結束當前的循環語句用於在for,while語句中
示例:
awk ‘BEGIN{sum=0;for(i=1;i<=100;i++) {if(i%2==0)continue;sum+=i}print sum}‘
awk ‘BEGIN{sum=0;for(i=1;i<=100;i++) {if(i==66)break;sum+=i}print sum}
因爲awk是逐行進行處理的,一行一行的處理,直到全部的行都被處理完結束,也至關於一個循環,next語句就至關於for、while循環語句的continue語句,用來結束對本行的處理而直接進入下一行處理。
示例:
awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
關聯數組array[index-expression]
Index-expression(下標):
1)下標可使用任意字符串;字符串要使用雙引號括起來,例:weekdays[「mon」]="Monday「
2)若是某數組元素事先不存在,在引用時,awk會自動建立此元素,並將其值初始化爲「空串
3)若要判斷數組中是否存在某元素,要使用「index in array」格式進行遍歷
4)若要遍歷數組中的每一個元素,需使用for循環
5)格式:for(var in array) {for-body} var會遍歷array的每一個索引
示例:
awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"] ="Tuesday";for(i in weekdays) {print weekdays[i]}}‘
netstat -tan | awk '/^tcp/{state[$NF]++}END {for(i in state) { print i,state[i]}}'
awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log
例圖:
使用awk查看一個文件中的每一行的重複次數
函數分爲系統函數和自定義函數,
數值處理:
rand():返回0和1之間一個隨機數;使用這個函數以前必須先寫一個srand()語句,才能產生隨機0到1之間的小數,保留6位,以下圖:
示例:產生10個0到100的隨機整數
字符串處理:
length([s]):返回指定字符串的長度,而且在這種模式下,不論是字母數字仍是漢字,都是一個佔用一個字符
sub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並將第一個匹 配的內容替換爲s
gsub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並所有替換 爲s所表示的內容
split(s,array,[r]):以r爲分隔符,切割字符串s,並將切割後的結果保存 至array所表示的數組中,第一個索引值爲1,第二個索引值爲2,…
例圖:
格式:
function name ( parameter, parameter, ... ) {
statements
return expression
}
執行機制:把函數編輯在一個文件中,name是函數的名字,parameter是虛參,調用函數的括號內的實參,每個實參對應着一個虛參,在函數中虛參是調用實參的值來執行statement部分的表達式,return的做用相似shell中的echo,是打印結果在終端上,expression能夠是變量名或者是表達式,
示例:編輯文件abc,寫一個函數,要求取最大值,
格式:system(「cmd」)