Linux系統管理——GNU awk使用方法及技巧
阿新 • • 發佈:2018-06-06
awk 文本日誌處理 1、awk
基本用法: awk [options] ‘program’ var=value file… awk [options] -f programfile var=value file… awk [options] 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file ... awk 程序通常由: BEGIN語句塊、能夠使用模式匹配的通用語句塊、END語句塊,共3部分組成 program通常是被單引號或雙引號中
選項: -F 指明輸入時用到的字段分隔符 -v var=value: 自定義變量
1.1、基本格式
基本格式:awk [options] 'program' file… program:pattern{action statements;..} pattern和action: ? pattern部分決定動作語句何時觸發及觸發事件 BEGIN,END ? action statements對數據進行處理,放在{}內指明print, printf;
分割符、域和記錄 ? awk執行時,由分隔符分隔的字段(域)標記$1,$2..$n稱 為域標識。 $0為所有域,註意:和shell中變量$符含義不同 ? 文件的每一行稱為記錄 ? 省略action,則默認執行 print $0 的操作
1.2、awk工作原理
第一步:執行 BEGIN{action;… }語句塊中的語句; 第二步:從文件或標準輸入(stdin)讀取一行,然後執行pattern{ action;… }語句塊,它逐行掃描文件,從第一行到最後一行重復這 個過程,直到文件全部被讀取完畢。 第三步:當讀至輸入流末尾時,執行END{action;…}語句塊; BEGIN語句塊在awk開始從輸入流中讀取行之前被執行,這是一個 可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通常 可以寫在BEGIN語句塊中; END語句塊在awk從輸入流中讀取完所有的行之後即被執行,比如 打印所有行的分析結果這類信息匯總都是在END語句塊中完成,它 也是一個可選語句塊; pattern語句塊中的通用命令是最重要的部分,也是可選的。如果 沒有提供pattern語句塊,則默認執行{ print },即打印每一個讀取 到的行,awk讀取的每一行都會執行該語句塊。
1.3、print格式
print格式:print item1, item2, ... 要點: (1) 逗號分隔符 (2) 輸出的各item可以字符串,也可以是數值;當前記錄的字段、 變量或awk的表達式 (3) 如省略item,相當於print $0 示例: awk '{print "hello,awk"}' awk –F: '{print}' /etc/passwd awk –F: ‘{print “wang”}’ /etc/passwd awk –F: ‘{print $1}’ /etc/passwd awk –F: ‘{print $0}’ /etc/passwd awk –F: ‘{print $1”\t”$3}’ /etc/passwd tail –3 /etc/fstab |awk ‘{print $2,$4}’
1.4、awk變量
變量:內置和自定義變量; 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 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
自定義變量(區分字符大小寫) (1) -v var=value (2) 在program中直接定義 示例: 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 cat awkscript {print script,$1,$2} awk -F: -f awkscript script=“awk” /etc/passwd
1.5、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 "%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
1.6、操作符
算術操作符: x+y, x-y, x*y, x/y, x^y, x%y -x: 轉換為負數 +x: 轉換為數值
字符串操作符:沒有符號的操作符,字符串連接
賦值操作符: =, +=, -=, *=, /=, %=, ^= ++, --
區別:
awk ‘BEGIN{i=0;print ++i,i}’ awk ‘BEGIN{i=0;print i++,i}’
比較操作符: ==, !=, >, >=, <, <= 模式匹配符: ~:左邊是否和右邊匹配包含 !~:是否不匹配
示例: 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
1.7、awk 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 -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
(4) line ranges:行範圍 startline,endline:/pat1/,/pat2/ 不支持直接給出數字格式; awk -F: ‘/^root\>/,/^nobody\>/{print $1}' /etc/passwd awk -F: ‘(NR>=10&&NR<=20){print NR,$1}' /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 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 '{i=!i;print i}‘ seq 10 | awk ‘!(i=!i)’ seq 10 |awk -v i=1 'i=!i'
1.8、awk action
常用的action分類 ? (1) Expressions:算術,比較表達式等 ? (2) Control statements:if, while等 ? (3) Compound statements:組合語句 ? (4) input statements ? (5) output statements:print等
2、awk控制語句
{ statements;… } 組合語句 if(condition) {statements;…} if(condition) {statements;…} else {statements;…} while(conditon) {statments;…} do {statements;…} while(condition) for(expr1;expr2;expr3) {statements;…} break continue delete array[index] delete array exit
2.1、if-else
語法: if(condition){statement;…}[else statement] if(condition1){statement1}else if(condition2){statement2} 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"}}'
2.2、while循環
語法:while(condition){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
2.3、do-while循環
語法:do {statement;…}while(condition) 意義:無論真假,至少執行一次循環體
示例: awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}‘
2.4、for循環
語法:for(expr1;expr2;expr3) {statement;…} 常見用法: for(variable assignment;condition;iteration process) {for-body}
特殊用法:能夠遍歷數組中的元素; for(var in array) {for-body}
示例: awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
性能比較: 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)
2.5、switch語句
語法: switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn} break和continue 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}‘
2.6、循環控制
break [n] continue [n] next: 提前結束對本行處理而直接進入下一行處理(awk自身循環) awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
3、awk數組
關聯數組:array[index-expression] index-expression: (1) 可使用任意字符串;字符串要使用雙引號括起來; (2) 如果某數組元素事先不存在,在引用時,awk會自動創建; 此元素,並將其值初始化為“空串” 若要判斷數組中是否存在某元素,要使用“index in array”格 式進行遍歷; 示例: weekdays[“mon”]="Monday“ awk 'BEGIN{weekdays["mon"]="Monday"; weekdays["tue"]="Tuesday";print weekdays["mon"]}‘ awk ‘!arr[$0]++’ dupfile awk '{!arr[$0]++;print $0, arr[$0]}' dupfile
若要遍歷數組中的每個元素,要使用for循環; 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
4、awk函數
數值處理: rand():返回0和1之間一個隨機數 awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }' 字符串處理: ? length([s]):返回指定字符串的長度 ? sub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並將第一個匹配的內容替換為s; echo "2008:08:08 08:08:08" | awk 'sub(/:/,“-",$1)' ? gsub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並全部替換為s所表示的內容; echo "2008:08:08 08:08:08" | awk ‘gsub(/:/,“-",$0)' ? split(s,array,[r]):以r為分隔符,切割字符串s,並將切割後的結果保存至array所表示的數組中,第一個索引值為1,第二個索引值為2,… netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'
自定義函數: 格式: function name ( parameter, parameter, ... ) { statements return expression } 示例: 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
5、awk中調用shell命令
system命令; 空格是awk中的字符串連接符,如果system中需要使用awk中 的變量可以使用空格分隔,或者說除了awk的變量外其他一律 用""引用起來。 awk BEGIN'{system("hostname") }' awk 'BEGIN{score=100; system("echo your score is " score) }'
6、awk腳本
將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
Linux系統管理——GNU awk使用方法及技巧