Linux之强大的gawk
awk介紹
awk是Linux文本處理工具三劍客之一,它是一種報表生成器,用于對文件內容進行各種"排版",然后進行格式化顯示。
在Linux上,我們使用的是GNU awk 簡稱gawk,其實,gawk就是awk的鏈接文件,因此,在系統上使用awk和gawk是一樣的
gawk是一種過程式編程語言,它支持條件判斷,數組,循環等各種編程語言中所有可以使用的功能,因此,我們還可以把gawk稱為一種腳本語言解釋器
awk是模式掃描和處理語言,該程序通常由:?BEGIN語句塊、能夠使用模式匹配的通用語句塊 、END語句塊,共3部分組成?
awk的三種運行方式:
(1) awk 命令行
awk(2) awk 程序文件
awk -f /path/from/awk_script(3) awk 腳本
#!/bin/awk -fawk 的基本用法
awk [options] 'program' var=value file ...awk [options] -f programfile var=value file ...awk [options] 'BEGIN{ action;...} pattern{ action;...} END{ action;... }' file ...?awk [options] 'program' FILE1 FILE2 ...
????program : PATTERN {ACTION STATEMENT}
????????program : 編程語言,通常是被單引號或雙引號引中
????????PATTERN : 模式,決定動作語句何時觸發及觸發事件 (BEGIN,END)
????????ACTION STATEMENT :動作語句,可以是由多個語句組成,各語句之間使用分號分割,,放在{}內指明 (print, printf)
????options :?
????????-F :指明輸入字段的分隔符,默認為空白字符
????????-v var=value : 自定義變量
分隔符,域和記錄:
????awk執行時,由分隔符分割的字段(域)標記 $1,$2,...$n 稱為域標識。$0表示所有域,注意,和shell變量中的$符號含義不同
????文件的每一行稱為記錄
????省略action,則默認執行 print $0 的操作
awk工作原理
第一步 : 執行BEGIN{ACTION;...}語句塊中的語句
第二步 : 從文件或標準輸入(stdin)讀取一行,然后執行 pattern{action;...}語句塊,它逐行掃描文件,從第一行到最后一行重復這個過程,直到文件全部被讀取完畢
第三步 : 當讀取至輸入流末尾時,執行END{ACTION;...}語句塊
BEGIN 語句塊在awk開始從輸入流中讀取之前被執行,這是一個可選的語句塊,比如變量初始化,打印輸出表格的表頭等語句通常可以寫在BEGIN語句塊中
END 語句塊在awk從輸入流中讀取完所有的行之后即被執行,比如打印所有行的分析結果這類信息匯總都是在END語句塊中完成,它也是一個可選語句塊
pattren 語句塊中的通用命令是最重要的部分,也是可選的。如果沒有提供pattern語句塊,則默認執行{print},既打印每一個讀取到的行,awk讀取的每一行都會執行該語句塊
awk命令
1, print
用法: print item1,item2,...
????item : 字符串,用引號引用
????變量 : 顯示變量的值,可以直接使用變量的名進行引用
????數值 : 無須加引號
要點:?
????(1) : 逗號分隔符
????(2) : 輸出的各item可以是字符串,也可以是數值,當前記錄的字段,變量或awk的表達式
????(3) : print后面的item省略時,相當于運行 print $0 ,用于輸出整行
示例:
awk?'{print?"hello?awk"}'?/etc/fstab awk?-F:?'{print?$1,$3}'?/etc/passwd awk?-F:?'{print?$1"\t"$3}'?/etc/passwd????
2, 變量?
????變量分為內建變量和自定義變量
2.1 內建變量
????FS : 輸入字段分隔符,默認為空白字符
awk -v FS=":" '{print $1,$3}' /etc/passwd awk -F: '{print $1,$3}' /etc/passwd????OFS : 輸出字段分隔符,默認為空白字符
awk -v FS=":" -v OFS="---" '{print $1,$3}' /etc/passwd????RS : 輸入記錄分隔符,指定輸入時的換行符,原換行符仍有效
awk -v RS=':' '{print}' /etc/passwd????ORS : 輸出記錄分隔符,輸出時用指定符號代替換行符
awk -v ORS='####' '{print}' /etc/passwd????NF : 字段的數量
awk -F: '{print NF}' /etc/passwdawk -F: '{print $(NF-1)}' /etc/passwd????NR : 行號
awk '{print NR}' /etc/fstab awk 'END{print NR}' /etc/fstab????FNR : 分別統計各文件的行號
awk '{print FNR}' /etc/fstab /etc/passwd????FILENAME : 當前文件名
awk 'END{print FILENAME}' /etc/fstab????ARGC : 命令行參數的個數,awk也算一個參數
awk '{print ARGC}' /etc/fstab /etc/passwd?????ARGV : 數組,保存的是命令行所給定的各參數
awk 'BEGIN{print ARGV[0]}' /etc/fstab??
2.2 自定義變量
????(1) -v var=vaule 變量名區分字符大小寫
????(2) 在program中直接定義
示例:
awk?-v?test='hello?awk'?'BEGIN{print?test}' awk?'BEGIN{test="hellp";print?test}'3, printf 命令
格式化輸出 : printf "FORMAT", item1.item2,...
????(1) 必須指定FORMAT
????(2) 不會自動換行,需要顯示給出換行控制符,\n
????(3) FORMAT 中需要分別為后面每個item指定格式符
格式符: 與 item 一一對應?
%c : 顯示字符的ascii碼%d,%i : 顯示十進制整數%e,%E : 科學計數法數值顯示%f : 顯示為浮點數%g,%G : 以科學計數法或浮點形式顯示數值%s : 顯示字符串%u : 無符號整形%% : 顯示%自身修飾符:
#[.#] : 第一個數字控制顯示的寬度,第二個#表示小數點后的精度 ?%3.1f ?
- : 左對齊 (默認右對齊) ?%-15s
+ : 顯示數值的符號 ?%+d
示例:
awk?-F:?'{printf?"%-15s%d\n",$1,$3}'?/etc/passwd awk?-F:?'{printf?"ername:?%s,UID:%d\n",$1,$3}'?/etc/passwd4,awk的操作符
操作符:
算術操作符:
+;-;*;/;^;%-x :轉換正負+x :把字符串轉換為數值字符串操作符:沒有符號的操作符表示字符串連接
賦值操作符:
=,+=,-=,*=,/=,%=,^=,--,++比較操作符:
>,>=,<=,!=,==模式匹配符:
~ : 是否匹配!~ : 不能夠匹配# awk –F: '$0 ~ /root/{print $1}' ?/etc/passwd?#?awk ?'$0 ?!~ /root/' ? /etc/passwd邏輯操作符:
&&;||;!示例:
awk -F: '$3>=500{print $1,$3}' /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(arg1,arg2,...)
條件表達式(三目表達式)
selector?if-true-expression:if-false-expression示例:
tail?-4?/etc/passwd|awk?-F:?'{$3>=500?usertype="common?users":usertype="system?users";printf?"%-15s%s\n",$1,usertype}'????
5,PATTERN 模式
pattern : 根據pattern條件,過濾匹配的行,在做處理
(1) 如果未指定,空模式,匹配文本的每一行
(2) [!]/regular expression/ : 僅處理能夠模式匹配到的行,需要用 / /括起來
awk?'/^UUID/{print?$1}'?/etc/fstab awk?'!/^UUID/{print?$1}'?/etc/fstab(3) relational expression : 關系表達式,結果有'真'有'假',結果為真時才會被處理
????真 : 結果為非0值,非空字符串
????假 : 結果為空字符串或0值
示例:
?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(4) line ranges : 行范圍
????
startline,endline : /part1/,/part2/ 不支持直接給出數字格式:
awk?-F:?'/^root/,/^nobody/{print}'?/etc/passwd awk?-F:?'NR>10&&NR<=15{print}'?/etc/passwd(5) BEGIN/END 模式
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?seq?10?|awk?'i=0'?seq?10?|awk?'i=1'seq?10?|?awk?'i=!i'seq?10?|?awk?'{i=!i;print?i}'??seq?10?|?awk?'!(i=!i)'?seq?10?|awk?-v?i=1?'i=!i'6,常用action
(1) Expression :算術,比較表達式等
(2) Control statements : if,while等
(3) Compound statements : 組合語句
(4) input statements
(5) output statements : print等
7,控制語句
if(condition){statements;...}if(condition){statements;...}else{statements;...}while(condition) {statements;...}do{statements;...} while(condition)for(expr1;expr2;expr3){statements;...}breakcontinuedelete array[index]delete arrayexit{statements;...} 組合語句7.1 if-else:
語法:?
if(condition)statement [else statement]if(condition1){statement1}else if(condition2){statement2} else{statement3}? awk?-F:?'{if($3>=500)print?$1,$3}'?/etc/passwd awk?-F:?'{if($3>=300)?{printf?"ok:%s\n",$1}?else?printf?"no:%s\n",$1}'?/etc/passwd df?-h?|?awk?-F'%'?'/^\/dev/{print?$1}'|awk?'{if($NF>4)print?$1}'使用場景:對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? df?-h|awk?-F%?'/^\/dev/{print?$1}'|awk?'$NF>=80{print?$1,$5}'7.2 while 循環:
語法: while(condition)statement
????條件為真,進入循環,條件為假,退出循環
使用場景:對一行內多個字段逐一類似處理時使用:對數組中的各元素逐一處理時使用
????length() 字段長度
awk?'/^[[:space:]]*linux/{i=1;while(i<=NF){print?$i,length($i);i++}}'?/etc/grub2.cfg????????#centos?7 awk?'/^[[:space:]]*linux/{i=1;while(i<=NF){if(length($i)>10)print?$i,length($i);i++}}'?/etc/grub2.cfg??#centos?77.3 do-while 循環:
語法: do {statement;...} while(condition)
????意義:無論真假,至少執行一次循環體
示例:
[root@centos6?~]#?awk?'BEGIN{sum=0;i=0;do{sum+=i;i++}while(i<=100)print?sum}' 50507.4 for 循環:
語法: for(expr1;expr2;expr3) {statement;...}
awk?'/^[[:space:]]*linux/{for(i=1;i<=NF;i++){print?$i,length($i)}}'?/etc/grub2.cfg特殊用法:
????可以遍歷數組中的每一個元素
????語法: for(var in array){condition}
性能比較(awk 和 shell 中for循環所需的時間)
time?(sum=0;for?i?in?{1..10000};do?let?sum+=i;done;echo?$sum) time?(awk?'BEGIN{sum=0;i=0;do{sum+=i;i++}while(i<=10000)print?sum}') time?(sum=0;for((i=0;i<=10000;i++));do?let?sum+=i;done;echo?$sum)7.5 switch語句
語法: switch(expression){case VALUE or /REGEXP/:statement;...;default:statement}
7.6 break和continue
7.7 next
提前結束對本行的處理而直接進入下一行
awk?-F:?'{if($3%2!=0)?next;print?$1,$3}'?/etc/passwd8,數組
關聯數組: array[index-expression]
index-expression :
(1) : 可使用任意字符串,字符串要使用雙引號括起來
(2) : 如果某數組元素事先不存在,在引用時,awk會自動創建此元素,并將其值初始化為"空串"
若要判斷數組中是否存在某元素,要使用"index in array"格式進行遍歷
awk?'BEGIN{weekdays["mon"]="Monday";?weekdays["tue"]="Tuesday";print?weekdays["mon"]}'? awk?'!a[$0]++'?dupfile若要遍歷數組中的每個元素,要使用for循環
for(var in array){for-body}
注意: var 會遍歷array的每個索引
awk?'BEGIN{k["a"]="aaa";k["b"]="bbb";for(i?in?k)print?k[i]}' netstat?-tan?|?awk?'NR>2{k[$NF]++;}END{for(i?in?k)print?k[i],i}'9,函數
數值處理:
????rand();返回0和1之間一個隨機數,這個產生的隨機數是不變的
????
????如果要產生隨機數,需要srand() 函數
awk 'BEGIN{srand() ;print int(rand()*1000000)}' #有點問題????
字符串處理:
????length([s]) : 返回指定字符串的長度
????sub(r,s,[t]) : 對t字符串進行搜索r表示的模式匹配的內容,并將第一次匹配的內容替換為s
????
? ? ?gsub(r,s,[t]) : 對t字符串進行搜索r表示的模式匹配的內容,并將匹配的所有內容都替換為s
????
????split(s,array,[r]) : 以r為分隔符,切割字符s,并將切割后的結果保存到array所表示的數組中,第一個索引值為1,不是0;第二個索引值為2;...
netstat?-ant?|?awk?'/^tcp\>/{split($5,ip,":");count[ip[1]]++?}END{for(i?in?count){print?i,count[i]}}'自定義函數:
函數:
function name (parameter,parameter,...){statementsreturn expression}示例:
????#cat fun.awk
function max(a,b){a>b?var=a:var=breturn var}BEGIN{a=3;b=2;print max(a,b)} awk -f fun.awk ?????
awk中調用shell命令
system 命令
空格是 awk 中的字符串連接符,如果 system 中需要使用 awk 中的變量可以使用空格分隔,或者說除了awk的變量外其他一律用""引起來
awk腳本
將awk程序寫成腳本,直接調用或執行
比如:
??
向awk腳本參數
格式: awkfile var=value var2=value2 ... InputFile
示例:
? ?
練習
1、統計/etc/fstab文件中每個文件系統類型出現的次數?
2、統計/etc/fstab文件中每個單詞出現的次數
3,求每班總成績和平均成績,成績表格式如下
name class score
wang ? 1 ? ?100
zhang ?2 ? ?90
li ? ? 1 ? ?80
awk?'BEGIN{print?"班級?總成績?平均成績"}{if($2==1){sum1+=$3;count1++}else?if($2==2)?{sum2+=$3;count2++}}END{printf?"?1?%7d???%3.2f\n",sum1?,sum1/count1;printf?"?2?%7d???%3.2f\n",sum2?,sum2/count2}'?test總結
以上是生活随笔為你收集整理的Linux之强大的gawk的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Saas浅谈
- 下一篇: 总结--linux常用配置文件总结