本章主要學習內(nèi)容
- awk介紹 ?
- awk基本用法 ?
- awk變量 ?
- awk格式化 ?
- awk操作符 ?
- awk條件判斷 ?
- awk循環(huán) ?
- awk數(shù)組 ?
- awk函數(shù) ?
- 調(diào)用系統(tǒng)命令
一.awk介紹
(一)awk:Aho, Weinberger, Kernighan壹店,報告生成器把兔,格式化文本輸出 ?
有多種版本:New awk(nawk)技羔,GNU awk( gawk) ?
gawk:模式掃描和處理語言 ?
基本用法: 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通常是被單引號或雙引號中
例: awk '{print 25}' /etc/passwd?image.png
引入BEGIN,END
例:awk 'BEGIN{print 35}' /etc/passwdimage.png
awk 'END{print 35}' /etc/passwd
選項:
-F 指明輸入時用到的字段分隔符
-v var=value: 自定義變量
(二)基本格式:awk [options] 'program' file… ?
program:pattern{action statements;..}
pattern和action:
? pattern部分決定動作語句何時觸發(fā)及觸發(fā)事件
BEGIN,END
? action statements對數(shù)據(jù)進行處理梗搅,放在{}內(nèi)指明 print, printf ? 分割符、域和記錄
? awk執(zhí)行時效览,由分隔符分隔的字段(域)標記$1,$2..$n稱 為域標識无切。$0為所有域,注意:和shell中變量$符含義不同
? 文件的每一行稱為記錄 ? 省略action丐枉,則默認執(zhí)行 print $0 的操作
二.awk工作原理
- 第一步:執(zhí)行BEGIN{action;… }語句塊中的語句 ?
- 第二步:從文件或標準輸入(stdin)讀取一行哆键,然后執(zhí)行pattern{ action;… }語句塊,它逐行掃描文件瘦锹,從第一行到最后一行重復這 個過程籍嘹,直到文件全部被讀取完畢。
- 第三步:當讀至輸入流末尾時弯院,執(zhí)行END{action;…}語句塊 ?
- BEGIN語句塊在awk開始從輸入流中讀取行之前被執(zhí)行辱士,這是一個 可選的語句塊,比如變量初始化听绳、打印輸出表格的表頭等語句通乘痰猓可以寫在BEGIN語句塊中 ?
- END語句塊在awk從輸入流中讀取完所有的行之后即被執(zhí)行,比如 打印所有行的分析結果這類信息匯總都是在END語句塊中完成椅挣,它 也是一個可選語句塊 ?
- pattern語句塊中的通用命令是最重要的部分头岔,也是可選的。如果 沒有提供pattern語句塊贴妻,則默認執(zhí)行{ print }切油,即打印每一個讀取 到的行,awk讀取的每一行都會執(zhí)行該語句塊
- print格式:print item1, item2, ... ?
要點:
(1) 逗號分隔符
(2) 輸出的各item可以字符串名惩,也可以是數(shù)值;當前記錄的字段孕荠、 變量或awk的表達式
(3) 如省略item娩鹉,相當于print $0
示例:
(1)awk '{print "welcome to magedu"}'image.png
(2) awk -F: '{print $1,$3}' /etc/passwd——默認以空格為分隔符image.png
(3)awk -F: '{print $1":"$3}' /etc/passwd——指定以“:”為分隔符
image.png
(4) awk -F: '{print "magedu"}' /etc/passwd——在/etc/passwd的每一行都打印"magedu"image.png
(5)awk -F: '{print}' /etc/fstab——不寫$1.....$n代表默認打印$0
image.png
(6)awk -F: '{print $1}'image.png
三.awk變量
- 變量:內(nèi)置和自定義變量 ?
FS:輸入字段分隔符攻谁,默認為空白字符
awk -v FS=':' '{print $1,FS,$3}’ /etc/passwd
例:
fs=":" ; awk -v FS=$fs '{print $1,FS,$3}' /etc/passwd
image.pngOFS:輸出字段分隔符,默認為空白字符
fs=":"; awk -v FS=$fs -v OFS="++++" '{print$1,$3}' /etc/passwd
image.png
RS:輸入記錄分隔符弯予,指定輸入時的換行符戚宦,原換行符仍有效 ?
例子:image.png
ORS:輸出記錄分隔符,輸出時用指定符號代替換行符
例子:awk -v RS=";" -v ORS="####" '{print $1,$3}' aaa.txt
image.png
NF:字段數(shù)量
awk -F: '{print NF}' /etc/passwd?image.png
awk -F : '{print $(NF-1)}' /etc/passwdimage.png
NR:行號
awk -F: '{print NR}' /etc/passwd
image.png
給/etc/fstab文件打印行號
awk '{print NR, $0}' /etc/fstabimage.png
FNR:各文件分別計數(shù),行號 ——效果就是如果同時讀取多個文件時锈嫩,可以分別進行計數(shù)打印行號受楼,如果用NR則會將多個文件累加打印
例:
awk '{print NR}' /etc/fstab /etc/inittabimage.png
使用FNR則會解決該問題
awk '{print FNR}' /etc/fstab /etc/inittab
image.png
FILENAME:當前文件名
awk '{print FILENAME,NR,$0}' /etc/fstab
image.png
ARGC:命令行參數(shù)的個數(shù)
awk '{print ARGC}’ /etc/fstab /etc/inittab
awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab
image.png
ARGV:數(shù)組,保存的是命令行所給定的各參數(shù)
awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittabimage.png
awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab——代表第二參數(shù)呼寸,為/etc/fstabawk變量
自定義變量(區(qū)分字符大小寫)
(1) -v var=value
(2) 在program中直接定義 ?
示例:
awk -v name="zhang" '{print name }' /etc/fstab
image.png
awk -v name="zhang" 'BEGIN{print name, "is ceo" }image.png
也可以直接在{}里面定義
awk '{sex=male;age=18;print sex,age}' aaa.txtimage.png
注意:{print sex ,age ;age=18},打印出來的效果是第一行不打印年齡image.png
也支持調(diào)用文件來實現(xiàn)
vim aaa.txt
{sex="male";age=18;print $1,male,age}
awk -F: -f aaa.txt /etc/passwd
image.png規(guī)律是先賦值后定義艳汽,否則會出現(xiàn)一些錯誤
四.awk中的printf命令
格式化輸出:printf “FORMAT”, item1, item2, ...
- (1) 必須指定FORMAT
- (2) 不會自動換行,需要顯式給出換行控制符对雪,\n
- (3) FORMAT中需要分別為后面每個item指定格式符 ?
格式符:與item一一對應
%c: 顯示字符的ASCII碼
%d, %i: 顯示十進制整數(shù)
%e, %E:顯示科學計數(shù)法數(shù)值
%f:顯示為浮點數(shù)
%g, %G:以科學計數(shù)法或浮點形式顯示數(shù)值
%s:顯示字符串
%u:無符號整數(shù)
%%: 顯示%自身 ?
修飾符: #[.#]:
第一個數(shù)字控制顯示的寬度河狐;
第二個#表示小數(shù)點后精度,%3.1f
-: 左對齊(默認右對齊)
%-15s +:顯示數(shù)值的正負符號 %+d
示例:
(1)awk -F: '{print "%s" ,$1}' /etc/passwd——printf命令本身不具有換行命令瑟捣,所以不加\n,就不會自動換行
image.png
(2) awk -F : '{printf "%s\n",$1}' /etc/passwdimage.png
(3)awk -F : '{printf "%s %d\n" ,$1,$3}' /etc/passwdimage.png
(4)awk -F: '{printf "%-30s %-30d\n" ,$1,$3}' /etc/passwd
image.png
(5)awk -F: '{printf "%-30s %-10.3f" ,$1,$3}'
/etc/passwdimage.png
(6)awk -F: '{printf "username: %-20s uid: %-10d\n" ,$1,$3}' /etc/passwd
image.png
(7)awk -F: 'BEGIN{print "username uid"}{printf "%-20s %-10d\n" ,$1,$3}' /etc/passwd
image.png
(8) awk -F: 'BEGIN{printf "username uid\n-----------\n"}{printf "%-20s %-10d\n" ,$1,$3}' /etc/passwdimage.png
(9)df| grep "/dev/"|awk '{printf " username: %-20s use: %-10s\n" ,$1,$5}'image.png
五.操作符
(一) 算術操作符:
x+y, x-y, x*y, x/y, x^y, x%y
例:
awk 'BEGIN{print 2^3}'
awk 'BEGIN{print 2+3}'
awk 'BEGIN{print 2^3}'
-x: 轉換為負數(shù)
+x: 轉換為數(shù)值 ?
(二)字符串操作符:沒有符號的操作符馋艺,字符串連接 ?
賦值操作符: =, +=, -=, *=, /=, %=, ^= ++, -?
awk 'BEGIN{print i++}'
awk 'BEGIN{print ++i}'image.png
awk -v n=100 'BEGIN{sum=100;print sum+=n;pirnt sum }'
比較操作符: ==, !=, >, >=, <, <= ?
模式匹配符:~:左邊是否和右邊匹配包含
!~:是否不匹配
awk –F: '$0 ~ /root/{print $1}‘ /etc/passwd
awk -F : '$0 !~ /root/{print $1}' /etc/passwd
image.png
awk '$0~"^root" ' /etc/passwd——root 后不寫{print} 默認打印$0
也可以寫成 awk '$0~/^root/{print $0}' /etc/passwd
awk –F: '$3==0' /etc/passwdimage.png
(三)邏輯操作符:
與&&,或||迈套,非! ?
示例:
awk -F: ' $3>=100&&$3<=1000 {print $0}' /etc/passwd——$3是否大于100且小于1000捐祠,滿足條件打印結果?
image.png
awk -F: '$3>=1000|| $3<=100{print $3}' /etc/passwdimage.png
awk -F: '!($3==0){print $3}' /etc/passwd
(四)函數(shù)調(diào)用: function_name(argu1, argu2, ...) ?
條件表達式(三目表達式): selector?if-true-expression:if-false-expression
示例:
awlk -F: '{$3>=1000?usertype="commonuser":usertype="sysuser or sysadmin";printf "%-30s %-10s\n" ,$1,usertype}' /etc/passwd
image.png
解釋:首先判斷$3是否大于1000,如果大于一千則顯示用戶類型為'commonuser',當小于一千時桑李,則顯示用戶類型為'sysuser or sysadmin'雏赦,然后格式化打印用戶名和用戶類型。注意字符串一定要加雙引號
(五) awk PATTERN
awk PATTERN:根據(jù)pattern條件芙扎,先過濾匹配的行祭埂,再做處理
(1)如果未指定:空模式,匹配每一行
image.png
(2) /regular expression/:僅處理能夠模式匹配到的行锻梳,需要用/ /括起來
awk '/^UUID/{print $1}' /etc/fstab
awk '!/^UUID/{print $1}' /etc/fstab
image.png
(3) relational expression: 關系表達式枢劝,結果為“真”才會被處理 真:結果為非0值,非空字符串
假:結果為空字符串或0值 ?
示例:
awk -F: 'i=1;j=1{print i,j}' /etc/passwd——判斷'i=1,j=1'結果為非0圈浇,所以為真寥掐,給每一行都會打印'i=1,j=1'image.png
awk ‘!0’ /etc/passwd ——非0結果為真
awk ‘!1’ /etc/passwd ——結果為0,為假磷蜀,不做后續(xù)處理
awk –F: '$3>=1000{print $1,$3}' /etc/passwd ——判斷$3是否大于一千召耘,如果大于一千則打印用戶名和UID
awk -F: '$3<1000{print $1,$3}' /etc/passwd——原理同上
awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd ——最后一個字段是否為/bin/bash,如果滿足則打印用戶名和最后一個字段
awk -F: '$NF ~ /bash$/{print $1,$NF}' /etc/passwd——最后一個字段是否是以/bash/結尾的,如果滿足則打印
(4) line ranges:行范圍
格式:startline,endline:/pat1/,/pat2/ 不支持直接給出數(shù)字
例子:
awk -F: '/root>/,/halt>/{print $1}' /etc/passwd ——判斷以root開頭褐隆,到以halt開頭匹配的行
image.png
awk -F: '(NR>=10&&NR<=20){print NR,$1}' /etc/passwd ?
(5) BEGIN/END模式
BEGIN{}: 僅在開始處理文件中的文本之前執(zhí)行一次
END{}:僅在文本處理完成之后執(zhí)行一次
示例:
awk -F: 'BEGIN{printf "username uid\n"}'{printf "%-20s %-10d\n "} END{printf "print end"}/etc/passwdimage.pngimage.png
seq 10 | awk 'i=0'——i=0為假污它,不執(zhí)行操作
seq 10 |awk 'i=1'——i=1為真,會打印
image.png
seq 10 |awk 'i=!0'——非0為真,執(zhí)行后續(xù)操作
seq 10 |awk 'i=!i'——i本身為0衫贬,因為之前沒有賦值德澈,但是加!表示非0固惯,所以會打印1梆造,當讀入第二個數(shù)字是,非i為假,不打印葬毫,所以最后的輸出結果為奇數(shù)
image.png
如果想打印偶數(shù)镇辉, seq 10 |awk -v i=1 'i=!i'image.png
或者seq 10 |awk '!(i=!i)' 效果也是打印偶數(shù)
如果想知道輸出的結果為真還是為假,可以 seq 10 |awk '{i=!i;print i}'image.png
六.awk控制語句
(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
image.png
awk -F : '{if($NF=="/bin/bash")print $1,$3 }' /etc/passwd——最后一個字段是否為/bin/bash,如果滿足贴捡,則打印
image.png
awk -F: '{if($3>=1000){printf username="common user %-20s %-10d\n " ,$1,$3}else{printf username="sysuser or sysadmin %-20s %-10d\n" ,$1,$3}}' /etc/passwdimage.png
也可寫成 awk -F: '{if ($3>=1000)printf usrename="common user %-20s\n" ,$1;else printf username="sysuser or root %-20s\n" ,$1}' /etc/passwd
df -h |awk -F: '/^/dev/{print $1}'|awk '$NF>10{print $NF}'image.png
awk 'BEGIN{test=680;if(test>=680)print "you can go to qinghua";else if (test<680$$test>=600)print "you can go to fudan";else print"you can go home"}'image.png
(2)while循環(huán) ?
語法:while(condition){statement;…} ? 條件“真”忽肛,進入循環(huán);條件“假”栈暇,退出循環(huán) ?使用場景: 對一行內(nèi)的多個字段逐一類似處理時使用 對數(shù)組中的各元素逐一處理時使用 ?
示例:
awk '/^[[:space:]]/linux16/{i=1;while (i<=NF){print $i,length($i);i++}}' /etc/grub2.cfg
解釋:首先規(guī)定是以空格開頭并后跟linux16的行麻裁,然后判斷字段數(shù)是否小于等于最后一個字段數(shù),如果滿足條件源祈,就打印字段內(nèi)容和字段的長度煎源。然后去匹配下一行,并且重新從i=1賦值香缺,繼續(xù)判斷循環(huán)
image.png
awk '/^[[:space:]]linux16/{i=1;while (i<=NF){if length($i)>=10{print $i length($i)};i++ }}' /etc/grub2.cfg
image.png
練習:
打印1到10手销,顯示數(shù)字是奇數(shù)還是偶數(shù)
seq 10|awk '{i=1;while(i<=NF){if ($i%2==0)print $i,"oushu";else print $i,"jishu";i++}}'
image.png
(3)do-while循環(huán) ?
語法:do {statement;…}while(condition) ?
意義:無論真假,至少執(zhí)行一次循環(huán)體
示例:
計算1加到100
方法1:
awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}'
方法2:
echo {1..100}|tr ' ' '+'|bc
方法3:
seq -s '+' 100|bc
方法4:
for ((sum=0;i=1;i<=100;i++));do let sum+=i;done echo $sum
image.png
方法5:
awk 'BEGIN{i=1;sum=0;while(i<=100){sum+=i;i++} print $sum}'
方法6:
awk 'BEGIN{for(i=1;i<=100;i++){sum+=i}print sum}'
image.png
(4)for循環(huán) ?
語法:for(expr1;expr2;expr3) {statement;…} ?
常見用法: for(variable assignment;condition;iteration process) {for-body} ?
特殊用法:能夠遍歷數(shù)組中的元素
語法:for(var in array) {for-body} ?
示例:
awk '/^[[:space:]]*linux/{for(i=1;i<=NF;i++){print $i length($i)}}'——尋找是否以空格開頭图张,并后跟linux16的行锋拖,打印每個字段的內(nèi)容,并顯示字段的長度
(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}'
效果是打印奇數(shù)祸轮,并相加求和
如果想打印偶數(shù)
awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}'
image.png
如果將continue換成break,效果是
image.png
原因:break 的功能是如果滿足條件兽埃,則跳出整個循環(huán),不再執(zhí)行适袜,所以第一個數(shù)為1柄错,屬于奇數(shù),滿足條件苦酱,直接退出售貌,顯示結果為0
而計算偶數(shù)時,因為1為奇數(shù)疫萤,不滿足條件颂跨,繼續(xù)計數(shù),直到第二個數(shù)進來扯饶,滿足條件恒削,則退出整個循環(huán)
練習:判斷i是否等于50池颈,如果等于退出循環(huán),不再計算
awk 'BEGIN{sum=0;for(i=1;i<=100;i++) {if(i==50)break;sum+=i}print sum}'
image.png
next: 提前結束對本行處理而直接進入下一行處理(awk自身循環(huán))
練習:
(1)awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd——判斷uid是否為偶數(shù)蔓同,是偶數(shù)則打印image.png
(2)用next打印用戶名打印偶數(shù)行(etc/passwd)
awk -F: '{if(NR%2!=0)next;print NR,$1,$3}' /etc/passwd
image.png
六.awk數(shù)組
關聯(lián)數(shù)組:
awk 'BEGIN{weekdays["mon"]="Monday"; weekdays["tue"]="Tuesday";print weekdays["mon"],weekdays[tue]}'
array[index-expression] ?
index-expression:
(1) 可使用任意字符串饶辙;字符串要使用雙引號括起來
(2) 如果某數(shù)組元素事先不存在蹲诀,在引用時斑粱,awk會自動創(chuàng)建 此元素,并將其值初始化為“空串”
若要判斷數(shù)組中是否存在某元素脯爪,要使用“index in array”格 式進行遍歷
示例:
weekdays[“mon”]="Monday“
image.png
image.png
練習:
統(tǒng)計/etc/passwd中最后一個字段shell類型则北,并對每個類型計數(shù)
awk -F: '{line[$7]++}END{for (i in line){print i,line[i] }}' /etc/passwd
image.png
若要遍歷數(shù)組中的每個元素,要使用for循環(huán) ?
for(var in array) {for-body} ?
注意:var會遍歷array的每個索引 ?
例子:
awk -F: '!line[$7]++' /etc/passwd——作用是去重痕慢,'!'代表非的意思尚揣,相同的shell類型只打印一次。
原理:初始化為0掖举,為假快骗,但是通過"!",變?yōu)檎妫蛴∫淮螌膕hell類型塔次,但是以后相同都不打印方篮,執(zhí)行完畢跳到下一行,繼續(xù)執(zhí)行新的shell類型的打印励负。
image.png
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 '{line[$1]++}END{for(i in line) {print i,line[i]}}' access_log
image.png
取出訪問的ip地址,并統(tǒng)計訪問數(shù)量
netstat -tan|awk -F: '[[:space:]]+' '/^tcp{ip[$6++]END{for(i in ip){print i,ip[i]}}'image.png
如果想要排序继榆,則在后面加入|sort -nr -k2|awk '{print $1}'|head -10
七.awk函數(shù)
數(shù)值處理: rand():返回0和1之間一個隨機數(shù)
awk 'BEGIN{print rand()}'——顯示固定的值巾表,并且為0和1之間的值
awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }' ?image.png
字符串處理:
? length([s]):返回指定字符串的長度
? sub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內(nèi)容,并將第一個匹 配的內(nèi)容替換為s
echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'
? gsub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內(nèi)容略吨,并全部替換 為s所表示的內(nèi)容
echo "2008:08:08 08:08:08" | awk ‘gsub(/:/,“-",$0)'
? split(s,array,[r]):以r為分隔符集币,切割字符串s,并將切割后的結果保存 至array所表示的數(shù)組中翠忠,第一個索引值為1,第二個索引值為2,…
netstat -tan | awk '/^tcp>/{split($5,ip,":");count[ip[1]]++} END{for (i in count) {print i,count[i]}}'
練習:
統(tǒng)計男生的總分數(shù)和平均數(shù)鞠苟,以及女生的總分數(shù)和平均數(shù)
image.png
方法1:
awk '{total[$3]+=$2;num[$3]++}END{for(name in total){print name,total[name],total[name]/num[name]}}'
image.png
方法2:awk '{if($3 == "male"){msum+=$2;mnum++}else{fsum+=$2;fnum++}}END{printf "msum=%d mavg=%.2f\n fsum=%d favg=%.2f\n",msum,msum/mnum,fsum,fsum/fnum }' score.txt
image.png
(2)自定義函數(shù) ?
格式: function name ( parameter, parameter, ... ) {
statements return expression
}
示例:
cat a.txt
function max(v1,v2) {
v1>v2?var=v1:var=v2
return var
}
BEGIN{
print max(a,b)}
awk -v a=10 -v b=20 –f a.txt
image.png
(3)system命令 ?
空格是awk中的字符串連接符,如果system中需要使用awk中 的變量可以使用空格分隔负间,或者說除了awk的變量外其他一律 用""引用起來偶妖。
awk 'BEGIN{system("hostname") }'image.png
awk 'BEGIN{score=100; system("echo your score is " score) }'
image.png
awk -v hi="haha" 'BEGIN{system("echo " hi)}'
image.png
str="hello,mage" ;awk -v hi="$str" 'BEGIN{system("echo "hi)}'
image.png