概述:
在之前的文章中,我們介紹過文本處理三劍客的grep、sed,本篇就簡要說明下awk的用法。主要是圍繞常見的一些用法進行展開,分為以下幾個部分:
1、awk的基礎語法
2、awk的進階語法
3、awk的實際效果演示
第一章 awk的基礎語法
1、awk的工作原理
每次讀取一行,按照指定字符分隔,然后按照指定動作處理
第一步:執行BEGIN{action;… }語句塊中的語句
第二步:從文件或標準輸入(stdin)讀取一行,然后執行pattern{action;… }語句塊,它逐行掃描文件,從第一行到最后一行重復這個過程,直到文件全部被讀取完畢。
第三步:當讀至輸入流末尾時,執行END{action;…}語句塊
BEGIN語句塊在awk開始從輸入流中讀取行之前被執行,這是一個可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通??梢詫懺贐EGIN語句塊中
END語句塊在awk從輸入流中讀取完所有的行之后即被執行,比如,打印所有行的分析結果這類信息匯總都是在END語句塊中完成,它也是一個可選語句塊
pattern語句塊中的通用命令是最重要的部分,也是可選的。如果沒有提供pattern語句塊,則默認執行{ print },即打印每一個讀取到的行, awk讀取的每一行都會執行該語句塊
如:BEGIN:所有行執行動作前的準備工作
awk -F: 'BEGIN{print "Username:\n———-"}$3>=500{print $1}' /etc/passwd
輸出結果為:
Username:
———-
nwc
END:所有行處理完成后,最后執行的收尾工作
awk -F: 'BEGIN{print "Username:\n———-"}$3>=500{print $1}END{print "———-"}' /etc/passwd
輸出結果為:
Username:
———-
nwc
———-
2、awk的基本用法:
awk [OPTIONS] 'SCRIPT' FILE…
awk [OPTIONS] '/PATTERN/{ACTION}' FILE…
awk 默認分隔符為空格,連續的多個空格會被當做一個空格,但是cut指定空格為分隔符時,只會認為單個空格為分隔
awk [options] -f programfile var=value file…
常用選項有:
-F 指定字段分隔符
可以指定多個分隔符,利用+號表示,例如:
ifconfig eth0|grep "inet addr"|awk -F "[ :]+" '{print $4,$6,$8}',指定空格和:為分隔符
-f /PATH/TO/FILE 指明awk處理的程序段的處理語句所在的文件路徑(也就是說awk支持將程序段的語句單獨寫在某個文件中,然后用-f進行指明即可)
-v VAR=VALUE 定義變量(變量也可以直接在動作內部直接定義,不用事先聲明)
例如:
awk -v num1=30 -v num2=20 ‘BEGIN{print num1+num2}’
結果是50
awk ‘BENGIN{num1=20;num2=30;print num1+num2}’
3、awk常用的4種分隔符:
輸入:
行分隔符:默認是\n也就是$符
字段分隔符:默認是空格
輸出:
行分隔符:默認是$
字段分隔符:默認是空格
如:awk -F : '/^root\>/{print "Usernam:"$1,"\nShell:"$7}' /etc/passwd
輸出為:Username:root
Shell:/bin/bash
如:awk -F : '/^root\>/{print "Usernam:",$1,"\nShell:",$7}' /etc/passwd
輸出為:Username: root
Shell: /bin/bash
如:awk -F : '/^root\>/{print "Usernam:",$1,"Shell:",$7}' /etc/passwd
輸出為:Username: root Shell: /bin/bash
可以在action動作內部定義變量:
awk 'BEGIN{FS=":";OFS="–"}$3>=500{print $1}' /etc/passwd
這樣也實現了指定分隔符為:冒號
4、awk的program段中pattern詳解
<1>空模式:匹配每一行
<2>/regular expression/:僅能處理被此處的模式匹配到的行
<3>relational expression:關系表達式,結果有“真”有“假”;結果為“真”才會被處理
真:結果為非0值,非空字符串
<4>地址定界:/PAT1/,/PAT2/ 從匹配到PAT1開始,到第一次匹配到PAT2結束,之間所有的行
不支持直接給出行號,如果要表示行號范圍,可使用NR>=10&&NR<=20方式
/PAT/:被PAT匹配到的所有的行
!/PAT/:被PAT匹配到的行之外的所有行
關系表達式(expression):表達式,如大于,小于,等于之類的,支持的符號有:
>:大于
<:小于
>=:大于等于
<=:小于等于
==:等于
!=:不等于
~:模式匹配,后面模式要用/PATTERN/這種表達式
例如:
awk -F: '$3 >= 500 && $3 <= 1000{print $1}' /etc/passwd
awk -F: '$7=="/bin/bash"{print $1}' /etc/passwd
也可寫成:
awk -F: '$7~/bash$/{print $1}' /etc/passwd
5、awk的program段中action詳解
默認為print,一個action內部有多條語句時,每個語句用;分號分隔
<1>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}
<2>printf
格式化輸出: printf “ FORMAT” , item1, item2, …
要點:
1)printf與print的最大不同是,printf需要指定格式
2)format用于指定后面的每個item的輸出格式
3)printf語句不會自動打印換行符 \n
4)整個format要用雙引號“”引起來
5)在format里面定義的格式的個數,要與后面的item個數匹配
format格式的指示符都以%開頭,后跟一個字符,常見的指示符如下:
%c 顯示字符的ASCII碼
%d,%i 顯示為十進制整數
%e,%E 科學計數法顯示數值
%f 顯示浮點數
%g,%G 以科學計數法的格式或浮點數的格式顯示數值
%s 顯示字符串
%u 無符號整數
%% 顯示%自身
format修飾符:
N 顯示寬度
– 左對齊
+ 顯示數值符號
如:%-15s
例如:awk -F: ‘{printf “%-15s %i\n”,$1,$3}’ /etc/passwd
在print和printf中也支持輸出重定向和管道
print items > output_file
print items >> output_file
print items | command
例如:awk -F :‘{printf “%-15s %i\n”,$1,$3 > “/dev/stderr”}’ /etc/passwd
6、awk的內置變量:
FS 讀入行時使用的字段分隔符,默認為空白
指定輸入分隔符:以指定:為例
OPTION段定義-F :
語句里面指定FS=":"
awk 'BEGIN{FS=":"}$3>=500{print $1}' /etc/passwd
OPTION段定義 -v FS=":"
OFS 輸出時指定字段分隔符,默認為空白
awk 'BEGIN{FS=":";OFS="–"}$3>=500{print $1}' /etc/passwd
RS 輸入時使用的換行符
ORS 輸出時使用的換行符
NF 當前行的字段個數
NR 文件的總行數,如果有多個文件,則是多個文件總行數之和
FNR 當前文件中正被處理的條目在文件中是第幾行,當有多個文件時,每個文件單獨計數
ARGV 數組,保存命令本身這個字符串,如:awk ‘{print $0}’ a.txt b.txt這個命令中,ARGV[0]保存awk 、ARGV[1]保存a.txt、ARGV[2]保存b.txt
ARGC awk命令的參數的個數
awk ‘BEGIN{print ARGC}’ a.txt b.txt結果是3
FILENAME awk命令說出你的文件的名稱
ENVIRON 當前shell環境變量及其值的關聯數組
$0 表示一整行
$1,$2。。。表示第幾個字段
length($1) 獲取第一個字段的字符串長度
第二章 awk的進階語法
awk的順序、選擇、循環,因為awk默認會自動的遍歷文件中的每一行,故awk選擇,循環的對象一般都是被分隔開來的各個字段
1、awk中的操作符:
算數操作符:
-x 負值
+x 轉換為數值
x^y x的y次方
x**y x的y次方
x*y 乘法
x/y 除法
x+y 加法
x-y 減法
x%y 取模,余數
賦值操作符:
=
+=
-=
*=
/=
%=
^=
**=
++
—
注意:如果某模式為=號,此時用/=/可能有語法錯誤,應該以/[=]/替代
比較操作符:
x < y x小于y為真,否則為假
x <= y x小于等于y為真,否則為假
x > y x大于y為真,否則為假
x >= y x大于等于y為真,否則為假
x == y x等于y為真,不等于為假
x != y x不等于y為真,等于為假
x ~ y x模式匹配y為真,不匹配為假
x !~ y x模式不匹配y為真,匹配為假
AA in array 某對象在指定的屬組里面為真,不在則為假
布爾值:
在awk中,0為假,任何非0值都為真(與bash中相反)
表達式之間的邏輯關系:
&&
||
2、三元條件表達式:
條件?為真表達式:為假表達式
相當于shell中的:
if 條件;then
為真表達式
else
為假表達式
fi
例如:
a=5
b=8
a>b?a is max:b is max
例如:
awk -v num1=20 -v num=30 ‘BEGIN{num1>num2?max=num1:max=num2;print max}’
3、awk中action段的if-else語句
語法:if (條件){為真表達式} else {為假表達式}
例如: awk '{if($3==0){print $1,"admin";}else{print $1,"user"}}' /etc/passwd 或: awk -F: ‘{if($1=="root")print $1,"admin";else print $1,"user"}’ /etc/passwd awk -F: ‘{if($1=="root")printf "%-15:%s\n",$1,"admin";else printf “%-15s:%s\n”,user}’ /etc/passwd awk -F: -v sum=0 ‘{if($3>=500)sum++}END{print sum}’ /etc/passwd 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"}}'
4、awk中action段的while語句
語法:while (條件){語句1;語句2;…}
例如: awk -F : ‘{i=1;while(i<=3){print $i;i++}}’ /etc/passwd awk -F : ‘{i=1;while (i<NF){if (lenth($i)>=4) {print $i};i++}}’ /etc/passwd awk ‘{i=1;while(i<NF){if($i>=100) print $i;i++}}’ hello.txt hello.txt文件的內容為一堆隨機數 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
5、awk中action段中的do-while語句:至少執行一次循環體,不管條件是否滿足
語法:do {語句1,語句2,…} while (condition)
例如: awk -F: ‘{i=1;do{print $i;i++}while(i<=3)}’ /etc/passwd awk -F: ‘{i=4;do{print $i;i--}while(i>4)}’ /etc/passwd
6、awk中action段中的for語句
語法:for(i=1;i<=5;i++){語句1,語句2,…}
例如: awk -F:‘{for(i=1;i<=3;i++)print $i}’ /etc/passwd awk -F: ‘{for(i=1;i<=NF;i++){if(length($i)>=4){print $i}}}’ /etc/passwd
for循環還可以用來遍歷數組元素,awk數組類似是關聯數組,也就是下標索引不是數字,而是字符串
語法:for(i in array){語句1,語句2,…}
awk -F:‘{$NF!~/^$/{BASH[$NF]++}END{for(A in BASH){printf "%15s:%i\n",A,BASH[A]}}’ /etc/passwd
單獨看這部分awk -F:‘{$NF!~/^$/{BASH[$NF]++}的內容的意義是:
當/etc/passwd中最后一個字段的值不為空時,將最后一個字段的值作為BASH數組的下標,然后對應BASH[$NF]的值+1,這樣就形成了數組中的元素:
BASH[/bin/bash] 值為一共有多少個對應shell的個數
最終就相當于統計出來了有多少種shell然后每種shell有多少個用戶使用
A in BASH在awk中遍歷的是數組的下標,而不是具體元素的值
7、awk中action段中case語句
語法:switch(表達式){case VALUE or /REGEXP/:語句1,語句2,…default:語句1,語句2,…}
8、awk中action段中的break、continue、next語句
break和continue:常用語循環或case語句中
next語句:
提前結束對本行文本的處理,并接著處理下一行
例如:
awk -F:‘{if($3%2==0)next;print $1,$3}’ /etc/passwd
作用是顯示ID號為奇數的用戶
awk的循環中,基本都是對字段進行循環,continue和break都只是進行下個字段,或者跳出本輪字段的循環,但是有些時候,需要跳出,進行下一行的循環,就需要用到next
9、awk中使用數組
array[index_expression]
index_expression可以使用任意字符串;需要注意的是,如果某數組元素時間不存在,那么在引用其時,awk會自動創建此元素并初始化為空串,因此要判斷某數組中是否存儲在元素,需要使用inde in array的方式
awk中使用的是關聯數組,也就是索引下標為字符串,當定義該數組和引用該數組時,索引下標都需要用“”雙引號引起來
關聯數組中的數據不是順序存放的,要遍歷數組,需要遍歷數組索引下標來引用
要遍歷數組中的每一個元素,需要使用如下的特殊結構:
for(VAR in array){語句1,…}
其中VAR 用于引用數組下標,而不是元素值
array[VAR] 數組中某一元素的值
如: netstat -tan | awk ‘/^tcp/{++S[$NF]}END{for(a in S)print a,S[a]}’ 作用是:每出現一個被/^tcp/模式匹配到的行,數組S[$NF]就加1,NF為當前匹配到的行的最后一個字段, 此處用其值作為數組S的元素索引下標 awk ‘{counts[$1]++};END{for(url in counts)print counts[url],url}’ /var/log/httpd/access_log 用法與上一個例子一樣,用于統計某日志文件中IP地址的訪問量
刪除數組變量
從關聯數組中刪除數組索引需要使用delete命令,其格式為:delete array[index]
10、awk中的內置函數:
<1>split(string,array [fieldsep])
功能是:將string表示的字符串以fieldsep為分隔符進行分割,并將分割后的結果保存至array為名的數組中,數組下表為從1開始的序列:
例如: netstat -tan | awk ‘/:80\>/{split($5,clients,":");IP[clients[1]]++}END{for(i in IP){print IP[i],i}}’|sort -rn|head -50 功能是顯示每個客戶端IP,及其請求的連接個數 netstat -tan | awk ‘/:80\>/{split($5,clients,":");ip[clients[4]]++}END{for(a in ip){print ip[a],a}}’|sort -rn|head -50 df -lh|awk '!/^File/{split($5,percnt,"%");if(percent[1]>=20){print $1}}' 顯示當前系統上磁盤空間占用率超過20%的分區
<2>length([string])
功能是:返回string字符串中字符的個數
<3>substr(string,start [,length])
功能是:取string字符串中的子串,從start開始,取length個,start從1開始計數
<4>sub(r,s,[t]):以r表示的模式來查找t所表示的字符串中的匹配的內容,并將其第一次出現替換為s所表示的字符串
<5>gsub(r,s,[t]):以r表示的模式來查找t所表示的字符串中的匹配的內容,并將其所有出現的位置均替換為s所表示的字符串
<6>system("command")
功能是:執行系統command命令,并將結果返回至awk命令
<7>systime() 功能是:取系統當前時間
<8>tolower(s) 功能是:將s中的所有字母轉為小寫
<9>toupper(s) 功能是:將s中的所有字母轉為大寫
<10>rand() 返回0和1之間的一個隨機數
awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }'
11、補充: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)
第三章 awk的實際效果演示
1、顯示GID小于500的組
[root@web ~]# awk -F: '{if($3>=500)printf "GroupName: %-10s GID: %-5i \n",$1,$3}' /etc/group GroupName: nfsnobody GID: 65534 GroupName: nnn GID: 500 GroupName: natasha GID: 506 GroupName: harry GID: 507 GroupName: sarah GID: 508 GroupName: mysql GID: 509 GroupName: sysadmins GID: 4331 GroupName: g1 GID: 4333 GroupName: nwc GID: 510 GroupName: bash GID: 511 GroupName: testbash GID: 512 GroupName: basher GID: 513 GroupName: nologin GID: 514 GroupName: gdm GID: 515 GroupName: testfind GID: 516 GroupName: sales GID: 4336 GroupName: mw GID: 3001
2、顯示默認shell為nologin的用戶
[root@web ~]# awk -F: '/\/nologin$/{print $1"====="$7}' /etc/passwd bin=====/sbin/nologin daemon=====/sbin/nologin adm=====/sbin/nologin lp=====/sbin/nologin mail=====/sbin/nologin uucp=====/sbin/nologin operator=====/sbin/nologin games=====/sbin/nologin gopher=====/sbin/nologin ftp=====/sbin/nologin ==================================================== awk -F: '$7~/nologin$/{print $1}' /etc/passwd awk -v FS=":" '/nologin$/{print $1}' /etc/passwd
3、顯示eth0網卡文件的配置信息,注意只顯示等號后面的值
[root@web ~]# awk -F "=" '{print $2}' /etc/sysconfig/network-scripts/ifcfg-eth0 eth0 10.1.32.68 255.255.0.0 10.1.0.1
4、顯示/etc/sysctl.conf文件中定義的內核參數,只顯示名稱
[root@web ~]# awk -F "=" '/^[^#]/{print $1}' /etc/sysctl.conf net.ipv4.ip_forward net.ipv4.conf.default.rp_filter net.ipv4.conf.default.accept_source_route kernel.sysrq kernel.core_uses_pid net.ipv4.tcp_syncookies kernel.msgmnb kernel.msgmax kernel.shmmax kernel.shmall [root@web ~]#
5、顯示eth0網卡的ip地址,通過ifconfig的命令結果進行過濾
[root@web ~]# ifconfig eth0 eth0 Link encap:Ethernet HWaddr 00:0C:29:AA:19:1B inet addr:10.1.32.68 Bcast:10.1.255.255 Mask:255.255.0.0 inet6 addr: fe80::20c:29ff:feaa:191b/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:388706 errors:0 dropped:0 overruns:0 frame:0 TX packets:3755 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:45528070 (43.4 MiB) TX bytes:396651 (387.3 KiB) [root@web ~]# ifconfig eth0|awk -F "[ :]+" '/inet addr/{print $4}' 10.1.32.68 [root@web ~]#
6、利用awk打印奇數行、偶數行
[root@web ~]# cat testfile1 1 2 3 4 5 6 7 8 9 10 [root@web ~]# awk 'a=!a{print $0}' testfile1 1 3 5 7 9 [root@web ~]# awk '!(a=!a){print $0}' testfile1 2 4 6 8 10 [root@web ~]# awk '{if(NR%2==0)print $0}' testfile1 2 4 6 8 10 [root@web ~]# awk '{if(NR%2==1)print $0}' testfile1 1 3 5 7 9 [root@web ~]#
7、統計ps aux命令執行結果中,系統上各狀態的進程的個數:
[root@web ~]# ps aux | awk '/^[^USER]/{stat[$8]++}END{for(i in stat){print i,stat[i]}}' S< 2 S<sl 1 Ss 18 SN 2 S 110 Ss+ 7 Ssl 2 R+ 1 S+ 1 Sl 1 S<s 1 [root@web ~]#
8、統計ps aux執行結果中,當前系統上各用戶的進程的個數
[root@localhost lib]# ps aux|awk 'NR>1{COUNT[$1]++}END{for(i in COUNT){print i,COUNT[i]}}' colord 1 chrony 1 rtkit 1 polkitd 1 dbus 1 nobody 1 gdm 3 libstor+ 1 avahi 2 postfix 2 root 412 [root@localhost lib]#
9、某成績單為:利用awk求每個班的平均分
姓名 分數 班級
a 10 1
b 20 2
c 30 1
d 40 3
e 50 1
f 60 2
g 70 1
h 80 4
i 90 1
j 100 2
k 110 3
l 120 2
[root@web ~]# cat file1 a 10 1 b 20 2 c 30 1 d 40 3 e 50 1 f 60 2 g 70 1 h 80 4 i 90 1 j 100 2 k 110 3 l 120 2 [root@web ~]# awk '{score[$3]+=$2;count[$3]++}END{for(i in score){for(j in count){if(i==j) {print "The Class: ",i," ","AVG_SCORE_IS: ",score[i]/count[j]}}}}' file1 The Class: 4 AVG_SCORE_IS: 80 The Class: 1 AVG_SCORE_IS: 50 The Class: 2 AVG_SCORE_IS: 75 The Class: 3 AVG_SCORE_IS: 75 [root@web ~]#
10、統計/etc/fstab文件中每個文件系統類型出現的次數
[root@web ~]# awk '/^[^#[:space:]]/{type[$3]++}END{for(i in type){print i,type[i]}}' /etc/fstab devpts 1 swap 1 sysfs 1 proc 1 tmpfs 1 ext4 4 [root@web ~]#
11、統計/etc/fstab文件中每個單詞出現的次數
[root@web ~]# cat /etc/fstab|tr -c '[a-z]' ' '|awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(j in count){print j,count[j]}}' cb 1 pages 1 ed 1 ee 2 info 1 disk 1 add 1 devpts 2 mode 1 tmpfs 2 ext 4 ccessible 1
原創文章,作者:M20-1倪文超,如若轉載,請注明出處:http://www.www58058.com/48016