shell编程之文本处理工具awk
shell編程之文本處理工具awk
文章目錄
- shell編程之文本處理工具awk
- 一、awk介紹
- 1. awk概述
- 2. awk能干啥?
- 二、awk使用方式
- 1. ==命令行模式使用==
- ㈠ 語法結構
- ㈡ 常用選項介紹
- ㈢ **=='==**命名部分說明**=='==**
- 2. 腳本模式使用
- ㈠ 腳本編寫
- ㈡ 腳本執行
- 三、 awk內部相關變量
- 1、==常用內置變量舉例==
- 2、內置變量分隔符舉例
- 四、 awk工作原理
- 五、awk使用進階
- 1. 格式化輸出`print`和`printf`
- 2. awk變量定義
- 3. awk中BEGIN...END使用
- ㈠ 舉例說明1
- ㈡ 舉例說明2
- 4. awk和正則的綜合運用
- ㈠ 舉例說明
- 4. 練習
- 5. awk的腳本編程
- ㈠ 流程控制語句
- ① if結構
- ② if...else結構
- ③ if...elif...else結構
- ㈡ 循環語句
- ① for循環
- ② while循環
- ③ 嵌套循環
- 6. awk算數運算
- 六、awk統計案例
- 1、統計系統中各種類型的shell
- 2、統計網站訪問狀態
- 3、統計訪問網站的每個IP的數量
- 4、統計網站日志中PV量
一、awk介紹
1. awk概述
-
awk是一種編程語言,主要用于在linux/unix下對文本和數據進行處理,是linux/unix下的一個工具。數據可以來自標準輸入、一個或多個文件,或其它命令的輸出。
-
awk的處理文本和數據的方式:逐行掃描文件,默認從第一行到最后一行,尋找匹配的特定模式的行,并在這些行上進行你想要的操作。
-
awk分別代表其作者姓氏的第一個字母。因為它的作者是三個人,分別是Alfred Aho、Brian Kernighan、Peter Weinberger。
-
gawk是awk的GNU版本,它提供了Bell實驗室和GNU的一些擴展。
-
下面介紹的awk是以GNU的gawk為例的,在linux系統中已把awk鏈接到gawk,所以下面全部以awk進行介紹。
2. awk能干啥?
二、awk使用方式
1. 命令行模式使用
㈠ 語法結構
awk 選項 '命令部分' 文件名特別說明: 引用shell變量需用雙引號引起㈡ 常用選項介紹
- -F 定義字段分割符號,默認的分隔符是空格
- -v 定義變量并賦值
㈢ '命名部分說明’
- 正則表達式,地址定位
- {awk語句1**;awk語句2;**…}
- BEGIN…END…
2. 腳本模式使用
㈠ 腳本編寫
#!/bin/awk -f 定義魔法字符 以下是awk引號里的命令清單,不要用引號保護命令,多個命令用分號間隔 BEGIN{FS=":"} NR==1,NR==3{print $1"\t"$NF} ...㈡ 腳本執行
方法1: awk 選項 -f awk的腳本文件 要處理的文本文件 awk -f awk.sh filenamesed -f sed.sh -i filename方法2: ./awk的腳本文件(或者絕對路徑) 要處理的文本文件 ./awk.sh filename./sed.sh filename三、 awk內部相關變量
| $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 | 當前輸入的文件名 |
1、常用內置變量舉例
# 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/nologin2、內置變量分隔符舉例
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工作原理
awk -F: '{print $1,$3}' /etc/passwd
awk使用一行作為輸入,并將這一行賦給內部變量$0,每一行也可稱為一個記錄,以換行符(RS)結束
每行被間隔符**:**(默認為空格或制表符)分解成字段(或域),每個字段存儲在已編號的變量中,從$1開始
awk使用print函數打印字段,打印出來的字段會以空格分隔,因為$1,$3之間有一個逗號。逗號比較特殊,它映射為另一個內部變量,稱為輸出字段分隔符OFS,OFS默認為空格
awk處理完一行后,將從文件中獲取另一行,并將其存儲在$0中,覆蓋原來的內容,然后將新的字符串分隔成字段并進行處理。該過程將持續到所有行處理完畢
五、awk使用進階
1. 格式化輸出print和printf
print函數 類似echo "hello world" # date |awk '{print "Month: "$2 "\nYear: "$NF}' # awk -F: '{print "username is: " $1 "\t uid is: "$3}' /etc/passwdprintf函數 類似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/passwdawk 'BEGIN{FS=":"};{printf "%-15s %-15s %-15s\n",$1,$6,$NF}' a.txt%s 字符類型 strings %-20s %d 數值類型 占15字符 - 表示左對齊,默認是右對齊 printf默認不會在行尾自動換行,加\n2. awk變量定義
# 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中調用定義的變量不需要加$3. awk中BEGIN…END使用
? ①BEGIN:表示在程序開始前執行
? ②END :表示所有文件處理完后執行
? ③用法:'BEGIN{開始處理之前};{處理中};END{處理結束后}'
㈠ 舉例說明1
打印最后一列和倒數第二列(登錄shell和家目錄)
awk -F: 'BEGIN{ print "Login_shell\t\tLogin_home\n*******************"};{print $NF"\t\t"$(NF-1)};END{print "************************"}' 1.txtawk 'BEGIN{ FS=":";print "Login_shell\tLogin_home\n*******************"};{print $NF"\t"$(NF-1)};END{print "************************"}' 1.txtLogin_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 ************************************㈡ 舉例說明2
打印/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}4. awk和正則的綜合運用
| == | 等于 |
| != | 不等于 |
| > | 大于 |
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
| ~ | 匹配 |
| !~ | 不匹配 |
| ! | 邏輯非 |
| && | 邏輯與 |
| || | 邏輯或 |
㈠ 舉例說明
從第一行開始匹配到以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}'4. 練習
5. awk的腳本編程
㈠ 流程控制語句
① if結構
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...else語句: if [ xxx ];thenxxxxxelsexxx 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…elif…else結構
if [xxxx];thenxxxx elif [xxx];thenxxx .... else ... fiif...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 userawk -F: '{ if($3==0) {print $1":管理員"} else if($3>=1 && $3<500 || $3==65534 ) {print $1":是系統用戶"} else {print $1":是普通用戶"}}' /etc/passwdawk -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/passwdawk -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㈡ 循環語句
① for循環
打印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}'② while循環
打印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++)) dofor ((x=1;x<=$y;x++))doecho -n $x done echo doneawk '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 56. awk算數運算
+ - * / %(模) ^(冪2^3) 可以在模式中執行計算,awk都將按浮點數方式執行算術運算 # awk 'BEGIN{print 1+1}' # awk 'BEGIN{print 1**1}' # awk 'BEGIN{print 2**3}' # awk 'BEGIN{print 2/3}'六、awk統計案例
1、統計系統中各種類型的shell
# awk -F: '{ shells[$NF]++ };END{for (i in shells) {print i,shells[i]} }' /etc/passwdbooks[linux]++ books[linux]=1 shells[/bin/bash]++ shells[/sbin/nologin]++/bin/bash 5 /sbin/nologin 6shells[/bin/bash]++ a shells[/sbin/nologin]++ b shells[/sbin/shutdown]++ cbooks[linux]++ books[php]++2、統計網站訪問狀態
# 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 13、統計訪問網站的每個IP的數量
# 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 |head4、統計網站日志中PV量
統計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
總結
以上是生活随笔為你收集整理的shell编程之文本处理工具awk的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: shell编程之文本处理工具sed
- 下一篇: 腾讯----贪吃的小Q