1、awk介紹
1.awk概述
2.awk能幹啥?
2、awk使用方式
1.==命令行模式使用==
1)語法結構
2)經常使用選項介紹
3)=='==命名部分說明=='==
2.腳本模式使用
1)腳本編寫
2)腳本執行
3、 awk內部相關變量
一、==經常使用內置變量舉例==
二、內置變量分隔符舉例
4、 awk工做原理
5、awk使用進階
1.格式化輸出print和printf
2.awk變量定義
3.awk中BEGIN...END使用
1)舉例說明1
2)舉例說明2
4.awk和正則的綜合運用
1)舉例說明
5.課堂練習
6.awk的腳本編程
1)流程控制語句
2)循環語句
7.awk算數運算
6、awk統計案例
一、統計系統中各類類型的shell
二、統計網站訪問狀態
三、統計訪問網站的每一個IP的數量
四、統計網站日誌中PV量php
gawk是awk的GNU版本,它提供了Bell實驗室和GNU的一些擴展。mysql
awk 選項 '命令部分' 文件名 特別說明: 引用shell變量需用雙引號引發
'/root/{awk語句}' sed中: '/root/p' 'NR==1,NR==5{awk語句}' sed中: '1,5p' '/^root/,/^ftp/{awk語句}' sed中:'/^root/,/^ftp/p'
'{print $0;print $1}' sed中:'p' 'NR==5{print $0}' sed中:'5p' 注:awk命令語句間用分號間隔
'BEGIN{awk語句};{處理中};END{awk語句}' 'BEGIN{awk語句};{處理中}' '{處理中};END{awk語句}'
#!/bin/awk -f 定義魔法字符 如下是awk引號裏的命令清單,不要用引號保護命令,多個命令用分號間隔 BEGIN{FS=":"} NR==1,NR==3{print $1"\t"$NF} ...
方法1: awk 選項 -f awk的腳本文件 要處理的文本文件 awk -f awk.sh filename sed -f sed.sh -i filename 方法2: ./awk的腳本文件(或者絕對路徑) 要處理的文本文件 ./awk.sh filename ./sed.sh filename
變量 | 變量說明 | 備註 |
---|---|---|
==$0== | 當前處理行的全部記錄 | |
==\$1,\$2,\$3...\$n== | 文件中每行以==間隔符號==分割的不一樣字段 | awk -F: '{print \$1,\$3}' |
==NF== | 當前記錄的字段數(列數) | awk -F: '{print NF}' |
==$NF== | 最後一列 | $(NF-1)表示倒數第二列 |
==FNR/NR== | 行號 | |
==FS== | 定義間隔符 | 'BEGIN{FS=":"};{print \$1,$3}' |
==OFS== | 定義輸出字段分隔符,==默認空格== | 'BEGIN{OFS="\t"};print \$1,$3}' |
RS | 輸入記錄分割符,默認換行 | 'BEGIN{RS="\t"};{print $0}' |
ORS | 輸出記錄分割符,默認換行 | 'BEGIN{ORS="\n\n"};{print \$1,$3}' |
FILENAME | 當前輸入的文件名 |
# awk -F: '{print $1,$(NF-1)}' 1.txt # awk -F: '{print $1,$(NF-1),$NF,NF}' 1.txt # awk '/root/{print $0}' 1.txt # awk '/root/' 1.txt # awk -F: '/root/{print $1,$NF}' 1.txt root /bin/bash # awk -F: '/root/{print $0}' 1.txt root:x:0:0:root:/root:/bin/bash # awk 'NR==1,NR==5' 1.txt # awk 'NR==1,NR==5{print $0}' 1.txt # awk 'NR==1,NR==5;/^root/{print $0}' 1.txt root:x:0:0:root:/root:/bin/bash root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
FS和OFS: # awk 'BEGIN{FS=":"};/^root/,/^lp/{print $1,$NF}' 1.txt # awk -F: 'BEGIN{OFS="\t\t"};/^root/,/^lp/{print $1,$NF}' 1.txt root /bin/bash bin /sbin/nologin daemon /sbin/nologin adm /sbin/nologin lp /sbin/nologin # awk -F: 'BEGIN{OFS="@@@"};/^root/,/^lp/{print $1,$NF}' 1.txt root@@@/bin/bash bin@@@/sbin/nologin daemon@@@/sbin/nologin adm@@@/sbin/nologin lp@@@/sbin/nologin [root@server shell07]# RS和ORS: 修改源文件前2行增長製表符和內容: vim 1.txt root:x:0:0:root:/root:/bin/bash hello world bin:x:1:1:bin:/bin:/sbin/nologin test1 test2 # awk 'BEGIN{RS="\t"};{print $0}' 1.txt # awk 'BEGIN{ORS="\t"};{print $0}' 1.txt
awk -F: '{print $1,$3}' /etc/passwd
linux
awk使用一行做爲輸入,並將這一行賦給內部變量$0,每一行也可稱爲一個記錄,以換行符(RS)結束正則表達式
每行被間隔符==:==(默認爲空格或製表符)分解成字段(或域),每一個字段存儲在已編號的變量中,從$1開始sql
問:awk如何知道用空格來分隔字段的呢?shell
答:由於有一個內部變量==FS==來肯定字段分隔符。初始時,FS賦爲空格編程
awk使用print函數打印字段,打印出來的字段會以==空格分隔==,由於\$1,\$3之間有一個逗號。逗號比較特殊,它映射爲另外一個內部變量,稱爲==輸出字段分隔符==OFS,OFS默認爲空格vim
print
和printf
print函數 相似echo "hello world" # date |awk '{print "Month: "$2 "\nYear: "$NF}' # awk -F: '{print "username is: " $1 "\t uid is: "$3}' /etc/passwd printf函數 相似echo -n # awk -F: '{printf "%-15s %-10s %-15s\n", $1,$2,$3}' /etc/passwd # awk -F: '{printf "|%15s| %10s| %15s|\n", $1,$2,$3}' /etc/passwd # awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd awk 'BEGIN{FS=":"};{printf "%-15s %-15s %-15s\n",$1,$6,$NF}' a.txt %s 字符類型 strings %-20s %d 數值類型 佔15字符 - 表示左對齊,默認是右對齊 printf默認不會在行尾自動換行,加\n
# awk -v NUM=3 -F: '{ print $NUM }' /etc/passwd # awk -v NUM=3 -F: '{ print NUM }' /etc/passwd # awk -v num=1 'BEGIN{print num}' 1 # awk -v num=1 'BEGIN{print $num}' 注意: awk中調用定義的變量不須要加$
①==BEGIN==:表示在==程序開始前==執行瀏覽器
②==END== :表示全部文件==處理完後==執行bash
③用法:'BEGIN{開始處理以前};{處理中};END{處理結束後}'
打印最後一列和倒數第二列(登陸shell和家目錄)
awk -F: 'BEGIN{ print "Login_shell\t\tLogin_home\n*******************"};{print $NF"\t\t"$(NF-1)};END{print "************************"}' 1.txt awk 'BEGIN{ FS=":";print "Login_shell\tLogin_home\n*******************"};{print $NF"\t"$(NF-1)};END{print "************************"}' 1.txt Login_shell Login_home ************************ /bin/bash /root /sbin/nologin /bin /sbin/nologin /sbin /sbin/nologin /var/adm /sbin/nologin /var/spool/lpd /bin/bash /home/redhat /bin/bash /home/user01 /sbin/nologin /var/named /bin/bash /home/u01 /bin/bash /home/YUNWEI ************************************
打印/etc/passwd裏的用戶名、家目錄及登陸shell
u_name h_dir shell *************************** *************************** awk -F: 'BEGIN{OFS="\t\t";print"u_name\t\th_dir\t\tshell\n***************************"};{printf "%-20s %-20s %-20s\n",$1,$(NF-1),$NF};END{print "****************************"}' # awk -F: 'BEGIN{print "u_name\t\th_dir\t\tshell" RS "*****************"} {printf "%-15s %-20s %-20s\n",$1,$(NF-1),$NF}END{print "***************************"}' /etc/passwd 格式化輸出: echo print echo -n printf {printf "%-15s %-20s %-20s\n",$1,$(NF-1),$NF}
運算符 | 說明 |
---|---|
== | 等於 |
!= | 不等於 |
> | 大於 |
< | 小於 |
>= | 大於等於 |
<= | 小於等於 |
~ | 匹配 |
!~ | 不匹配 |
! | 邏輯非 |
&& | 邏輯與 |
|| | 邏輯或 |
從第一行開始匹配到以lp開頭行 awk -F: 'NR==1,/^lp/{print $0 }' passwd 從第一行到第5行 awk -F: 'NR==1,NR==5{print $0 }' passwd 從以lp開頭的行匹配到第10行 awk -F: '/^lp/,NR==10{print $0 }' passwd 從以root開頭的行匹配到以lp開頭的行 awk -F: '/^root/,/^lp/{print $0}' passwd 打印以root開頭或者以lp開頭的行 awk -F: '/^root/ || /^lp/{print $0}' passwd awk -F: '/^root/;/^lp/{print $0}' passwd 顯示5-10行 awk -F':' 'NR>=5 && NR<=10 {print $0}' /etc/passwd awk -F: 'NR<10 && NR>5 {print $0}' passwd 打印30-39行以bash結尾的內容: [root@MissHou shell06]# awk 'NR>=30 && NR<=39 && $0 ~ /bash$/{print $0}' passwd stu1:x:500:500::/home/stu1:/bin/bash yunwei:x:501:501::/home/yunwei:/bin/bash user01:x:502:502::/home/user01:/bin/bash user02:x:503:503::/home/user02:/bin/bash user03:x:504:504::/home/user03:/bin/bash [root@MissHou shell06]# awk 'NR>=3 && NR<=8 && /bash$/' 1.txt stu7:x:1007:1007::/rhome/stu7:/bin/bash stu8:x:1008:1008::/rhome/stu8:/bin/bash stu9:x:1009:1009::/rhome/stu9:/bin/bash 打印文件中1-5而且以root開頭的行 [root@MissHou shell06]# awk 'NR>=1 && NR<=5 && $0 ~ /^root/{print $0}' 1.txt root:x:0:0:root:/root:/bin/bash [root@MissHou shell06]# awk 'NR>=1 && NR<=5 && $0 !~ /^root/{print $0}' 1.txt bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 理解;號和||的含義: [root@MissHou shell06]# awk 'NR>=3 && NR<=8 || /bash$/' 1.txt [root@MissHou shell06]# awk 'NR>=3 && NR<=8;/bash$/' 1.txt 打印IP地址 # ifconfig eth0|awk 'NR>1 {print $2}'|awk -F':' 'NR<2 {print $2}' # ifconfig eth0|grep Bcast|awk -F':' '{print $2}'|awk '{print $1}' # ifconfig eth0|grep Bcast|awk '{print $2}'|awk -F: '{print $2}' # ifconfig eth0|awk NR==2|awk -F '[ :]+' '{print $4RS$6RS$8}' # ifconfig eth0|awk -F"[ :]+" '/inet addr:/{print $4}'
[root@MissHou ~] awk '/bash$/{print $0}' /etc/passwd [root@MissHou ~] awk '/bash$/{print $0}' /etc/passwd [root@MissHou ~] awk '/bash$/' /etc/passwd [root@MissHou ~] awk -F: '$7 ~ /bash/' /etc/passwd [root@MissHou ~] awk -F: '$NF ~ /bash/' /etc/passwd [root@MissHou ~] awk -F: '$0 ~ /bash/' /etc/passwd [root@MissHou ~] awk -F: '$0 ~ /\/bin\/bash/' /etc/passwd
# awk -F: '$0 ~ /\/bin\/bash/{print $1}' /etc/passwd
500 stu1 501 yunwei 502 user01 503 user02 504 user03 # awk -F: 'BEGIN{print "UID\tUSERNAME"} {if($3>=500 && $3 !=65534 ) {print $3"\t"$1} }' /etc/passwdUID USERNAME # awk -F: '{if($3 >= 500 && $3 != 65534) print $1,$3}' a.txt redhat 508 user01 509 u01 510 YUNWEI 511
if語句: if [ xxx ];then xxx fi 格式: awk 選項 '正則,地址定位{awk語句}' 文件名 { if(表達式){語句1;語句2;...}} awk -F: '{if($3>=500 && $3<=60000) {print $1,$3} }' passwd # awk -F: '{if($3==0) {print $1"是管理員"} }' passwd root是管理員 # awk 'BEGIN{if('$(id -u)'==0) {print "admin"} }' admin
if...else語句: if [ xxx ];then xxxxx else xxx fi 格式: {if(表達式){語句;語句;...}else{語句;語句;...}} awk -F: '{ if($3>=500 && $3 != 65534) {print $1"是普通用戶"} else {print $1,"不是普通用戶"}}' passwd awk 'BEGIN{if( '$(id -u)'>=500 && '$(id -u)' !=65534 ) {print "是普通用戶"} else {print "不是普通用戶"}}'
if [xxxx];then xxxx elif [xxx];then xxx .... else ... fi if...else if...else語句: 格式: { if(表達式1){語句;語句;...}else if(表達式2){語句;語句;...}else if(表達式3){語句;語句;...}else{語句;語句;...}} awk -F: '{ if($3==0) {print $1,":是管理員"} else if($3>=1 && $3<=499 || $3==65534 ) {print $1,":是系統用戶"} else {print $1,":是普通用戶"}}' awk -F: '{ if($3==0) {i++} else if($3>=1 && $3<=499 || $3==65534 ) {j++} else {k++}};END{print "管理員個數爲:"i "\n系統用戶個數爲:"j"\n普通用戶的個數爲:"k }' # awk -F: '{if($3==0) {print $1,"is admin"} else if($3>=1 && $3<=499 || $3==65534) {print $1,"is sys users"} else {print $1,"is general user"} }' a.txt root is admin bin is sys users daemon is sys users adm is sys users lp is sys users redhat is general user user01 is general user named is sys users u01 is general user YUNWEI is general user awk -F: '{ if($3==0) {print $1":管理員"} else if($3>=1 && $3<500 || $3==65534 ) {print $1":是系統用戶"} else {print $1":是普通用戶"}}' /etc/passwd awk -F: '{if($3==0) {i++} else if($3>=1 && $3<500 || $3==65534){j++} else {k++}};END{print "管理員個數爲:" i RS "系統用戶個數爲:"j RS "普通用戶的個數爲:"k }' /etc/passwd 管理員個數爲:1 系統用戶個數爲:28 普通用戶的個數爲:27 # awk -F: '{ if($3==0) {print $1":是管理員"} else if($3>=500 && $3!=65534) {print $1":是普通用戶"} else {print $1":是系統用戶"}}' passwd awk -F: '{if($3==0){i++} else if($3>=500){k++} else{j++}} END{print i; print k; print j}' /etc/passwd awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print "管理員個數: "i; print "普通用個數: "k; print "系統用戶: "j}' /etc/passwd 若是是普通用戶打印默認shell,若是是系統用戶打印用戶名 # awk -F: '{if($3>=1 && $3<500 || $3 == 65534) {print $1} else if($3>=500 && $3<=60000 ) {print $NF} }' /etc/passwd
打印1~5 for ((i=1;i<=5;i++));do echo $i;done # awk 'BEGIN { for(i=1;i<=5;i++) {print i} }' 打印1~10中的奇數 # for ((i=1;i<=10;i+=2));do echo $i;done|awk '{sum+=$0};END{print sum}' # awk 'BEGIN{ for(i=1;i<=10;i+=2) {print i} }' # awk 'BEGIN{ for(i=1;i<=10;i+=2) print i }' 計算1-5的和 # awk 'BEGIN{sum=0;for(i=1;i<=5;i++) sum+=i;print sum}' # awk 'BEGIN{for(i=1;i<=5;i++) (sum+=i);{print sum}}' # awk 'BEGIN{for(i=1;i<=5;i++) (sum+=i);print sum}'
打印1-5 # i=1;while (($i<=5));do echo $i;let i++;done # awk 'BEGIN { i=1;while(i<=5) {print i;i++} }' 打印1~10中的奇數 # awk 'BEGIN{i=1;while(i<=10) {print i;i+=2} }' 計算1-5的和 # awk 'BEGIN{i=1;sum=0;while(i<=5) {sum+=i;i++}; print sum }' # awk 'BEGIN {i=1;while(i<=5) {(sum+=i) i++};print sum }'
嵌套循環: #!/bin/bash for ((y=1;y<=5;y++)) do for ((x=1;x<=$y;x++)) do echo -n $x done echo done awk 'BEGIN{ for(y=1;y<=5;y++) {for(x=1;x<=y;x++) {printf x} ;print } }' # awk 'BEGIN { for(y=1;y<=5;y++) { for(x=1;x<=y;x++) {printf x};print} }' 1 12 123 1234 12345 # awk 'BEGIN{ y=1;while(y<=5) { for(x=1;x<=y;x++) {printf x};y++;print}}' 1 12 123 1234 12345 嘗試用三種方法打印99口訣表: #awk 'BEGIN{for(y=1;y<=9;y++) { for(x=1;x<=y;x++) {printf x"*"y"="x*y"\t"};print} }' #awk 'BEGIN{for(y=1;y<=9;y++) { for(x=1;x<=y;x++) printf x"*"y"="x*y"\t";print} }' #awk 'BEGIN{i=1;while(i<=9){for(j=1;j<=i;j++) {printf j"*"i"="j*i"\t"};print;i++ }}' #awk 'BEGIN{for(i=1;i<=9;i++){j=1;while(j<=i) {printf j"*"i"="i*j"\t";j++};print}}' 循環的控制: break 條件知足的時候中斷循環 continue 條件知足的時候跳過循環 # awk 'BEGIN{for(i=1;i<=5;i++) {if(i==3) break;print i} }' 1 2 # awk 'BEGIN{for(i=1;i<=5;i++){if(i==3) continue;print i}}' 1 2 4 5
+ - * / %(模) ^(冪2^3) 能夠在模式中執行計算,awk都將按浮點數方式執行算術運算 # awk 'BEGIN{print 1+1}' # awk 'BEGIN{print 1**1}' # awk 'BEGIN{print 2**3}' # awk 'BEGIN{print 2/3}'
# awk -F: '{ shells[$NF]++ };END{for (i in shells) {print i,shells[i]} }' /etc/passwd books[linux]++ books[linux]=1 shells[/bin/bash]++ shells[/sbin/nologin]++ /bin/bash 5 /sbin/nologin 6 shells[/bin/bash]++ a shells[/sbin/nologin]++ b shells[/sbin/shutdown]++ c books[linux]++ books[php]++
# ss -antp|grep 80|awk '{states[$1]++};END{for(i in states){print i,states[i]}}' TIME_WAIT 578 ESTABLISHED 1 LISTEN 1 # ss -an |grep :80 |awk '{states[$2]++};END{for(i in states){print i,states[i]}}' LISTEN 1 ESTAB 5 TIME-WAIT 25 # ss -an |grep :80 |awk '{states[$2]++};END{for(i in states){print i,states[i]}}' |sort -k2 -rn TIME-WAIT 18 ESTAB 8 LISTEN 1
# netstat -ant |grep :80 |awk -F: '{ip_count[$8]++};END{for(i in ip_count){print i,ip_count[i]} }' |sort # ss -an |grep :80 |awk -F":" '!/LISTEN/{ip_count[$(NF-1)]++};END{for(i in ip_count){print i,ip_count[i]}}' |sort -k2 -rn |head
統計Apache/Nginx日誌中某一天的PV量 <統計日誌> # grep '27/Jul/2017' mysqladmin.cc-access_log |wc -l 14519 統計Apache/Nginx日誌中某一天不一樣IP的訪問量 <統計日誌> # grep '27/Jul/2017' mysqladmin.cc-access_log |awk '{ips[$1]++};END{for(i in ips){print i,ips[i]} }' |sort -k2 -rn |head # grep '07/Aug/2017' access.log |awk '{ips[$1]++};END{for(i in ips){print i,ips[i]} }' |awk '$2>100' |sort -k2 -rn
名詞解釋:
==網站瀏覽量(PV)==
名詞:PV=PageView (網站瀏覽量)
說明:指頁面的瀏覽次數,用以衡量網站用戶訪問的網頁數量。屢次打開同一頁面則瀏覽量累計。用戶每打開一個頁面便記錄1次PV。
名詞:VV = Visit View(訪問次數)
說明:從訪客來到您網站到最終關閉網站的全部頁面離開,計爲1次訪問。若訪客連續30分鐘沒有新開和刷新頁面,或者訪客關閉了瀏覽器,則被計算爲本次訪問結束。
獨立訪客(UV)
名詞:UV= Unique Visitor(獨立訪客數)
說明:1天內相同的訪客屢次訪問您的網站只計算1個UV。
獨立IP(IP)
名詞:IP=獨立IP數
說明:指1天內使用不一樣IP地址的用戶訪問網站的數量。同一IP不管訪問了幾個頁面,獨立IP數均爲1
————————————本文到此爲止,感謝閱讀——————————————