詳細介紹AWK的文章,推薦去朱雙印的個人博客,10分好評的個人博客,傳送門
本文章僅為個人精簡參考使用,不適合初學者,詳細的介紹文章,請用以上的傳送門
也可以稍微參考一下博客園:https://www.cnblogs.com/isykw/p/6258781.html
也可以參考CSDN https://blog.csdn.net/sunchengquan/article/details/80276842
本文包括
- AWK簡介
- awk基本語法
- awk常用命令選項
- awk的幾種模式
- awk的內置變量
- awk設置定義變量
- awk模式的定義,空模式,關系運算模式,BEGIN模式,END模式,正則表達式模式
- awk 在用 {x,y} 這種正則時,需要加參數
- awk 支持if else, for ,while等控制語句
- awk 計算日志中ip的數量
- awk 把兩個文件內的指定列,合並成一個文件
- awk編程,善用FNR NR
- awk數學運算
- awk 生成隨機數(利用awk的自帶函數)
- awk中使用shell的環境變量
AWK簡介
awk是由Alfred Aho 、Peter Weinberger 和 Brian Kernighan這三個人創造的,awk由這個三個人的姓氏的首個字母組成。
awk早期是在unix上實現的,所以,我們現在在linux的所使用的awk其實是gawk,也就是GNU awk,簡稱為gawk,awk還有一個版本,New awk,簡稱為nawk,但是linux中最常用的還是gawk。
awk其實是一門編程語言,它支持條件判斷、數組、循環等功能。所以,我們也可以把awk理解成一個腳本語言解釋器。
awk 更適合格式化文本,以文件的行為處理單位的,對文本進行較復雜格式處理
AWK基礎
基本語法如下
awk [options] 'Pattern{Action}' file
awk '{
BEGIN{stat1}
BEGIN{stat2}
pattern1{action1}
pattern2{action2}
...
patternn{actionn}
{默認動作,無條件,始終執行}
END{stat1}
END{stat2}
}'
常用命令選項
-F 指定輸入分隔符,fs可以是字符串或正則表達式,如 -F ':' , 默認的隔符是空格
-v var=value -v是一種選項,var是一個變量的名稱,value是一個變量的值,有很多內置的變量名稱
-v FS=':' 指定輸入分隔符為: 和 -F 類似
-v OFS='###' 指定 輸出分隔符 ,默認輸出分隔符為空格,可以換成任意的輸出分割符
-f scripfile 從腳本文件中讀取awk命令
awk命令插入一個文件,並使awk程序可執行,然后awk命令解釋器作為腳本的首行,一遍通過鍵入腳本名稱來調用。
相當於shell腳本首行的:#!/bin/sh
可以換成:#!/bin/awk
如果只是顯示/etc/passwd的賬戶
#cat /etc/passwd |awk -F ':' '{print $1}' root daemon bin sys
AWK 包含兩種特殊的模式:BEGIN 和 END。
BEGIN 模式指定了處理文本之前需要執行的操作:
END 模式指定了處理完所有行之后所需要執行的操作:
以下實例展示了-v FS 指定輸入分隔符 和 -v OFS 指定輸出分隔符 指定BEGIN 和 END
awk 處理 /etc/passwd 獲取 $1,$7的數據
而賬戶與shell之間以'++++'分割,
而且在第一行添加文字 "name,shell",
在最后一行添加"blue,/bin/nosh"。
[root@cnblogs ~]# cat /etc/passwd |awk -v FS=':' -v OFS="++++" 'BEGIN {print "name,shell"} {print $1,$7} END {print "blue,/bin/nosh"}' name,shell root++++/bin/bash bin++++/sbin/nologin daemon++++/sbin/nologin ...
... blue,/bin/nosh
awk內置變量
awk有許多內置變量用來設置環境信息,這些變量可以被改變,下面給出了最常用的一些變量。
ARGC 命令行參數個數 ARGV ARGV內置變量表示的是一個數組,這個數組中保存的是命令行所給定的參數。這樣解釋還是很模糊,不容易理解,我們來看看示例。 ENVIRON 支持隊列中系統環境變量的使用 FILENAME awk瀏覽的文件名 FNR 各文件分別記錄的行號 FS FS: field separator設置輸入域分隔符,等價於命令行 -F選項 NF 列數,number of the field,當前處理行的總列數(被分成幾列) NR 行數,number of the row,當前處理文本行的行號 OFS OFS:output field separator 輸出字段分隔符, 默認為空白字符 ORS ORS:output row separator 輸出記錄分隔符(輸出換行符),輸出時用指定符號代替換行符 RS RS:row separator 輸入記錄分隔符(輸入換行符), 指定輸入時的換行符
除了內置變量,也可以定義自定義變量
有兩種定義方法
方法一:-v varname=value 變量名區分字符大小寫。
方法二:在program中直接定義。
[root@cnblogs ~]# awk -v myVAR="testVAR" 'BEGIN{print myVAR}' testVAR [root@cnblogs ~]# awk 'BEGIN{myVAR="testVAR";print myVAR}' testVAR
也可以一次定義多個,如
[root@cnblogs ~]# awk 'BEGIN{myVAR1="testVAR1";myVAR2="testVAR2";print myVAR1,myVAR2}' testVAR1 testVAR2
統計/etc/passwd:文件名,每行的行號,每行的列數,對應的完整行內容:
[root@cnblogs ~]# awk -F ':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin filename:/etc/passwd,linenumber:3,columns:7,linecontent:daemon:x:2:2:daemon:/sbin:/sbin/nologin filename:/etc/passwd,linenumber:4,columns:7,linecontent:adm:x:3:4:adm:/var/adm:/sbin/nologin filename:/etc/passwd,linenumber:5,columns:7,linecontent:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin filename:/etc/passwd,linenumber:6,columns:7,linecontent:sync:x:5:0:sync:/sbin:/bin/sync filename:/etc/passwd,linenumber:7,columns:7,linecontent:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
使用printf替代print,可以讓代碼更加簡潔,易讀
[root@cnblogs ~]# awk -F ':' '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin filename:/etc/passwd,linenumber:3,columns:7,linecontent:daemon:x:2:2:daemon:/sbin:/sbin/nologin filename:/etc/passwd,linenumber:4,columns:7,linecontent:adm:x:3:4:adm:/var/adm:/sbin/nologin filename:/etc/passwd,linenumber:5,columns:7,linecontent:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin filename:/etc/passwd,linenumber:6,columns:7,linecontent:sync:x:5:0:sync:/sbin:/bin/sync filename:/etc/passwd,linenumber:7,columns:7,linecontent:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
AWK模式的概念就是條件
"模式"這個詞聽上去文縐縐的,不是特別容易理解,那么我們換一種說法,我們把"模式"換成"條件",可能更容易理解,那么"條件"是什么意思呢?我們知道,awk是逐行處理文本的,也就是說,awk會先處理完當前行,再處理下一行,如果我們不指定任何"條件",awk會一行一行的處理文本中的每一行,如果我們指定了"條件",只有滿足"條件"的行才會被處理,不滿足"條件"的行就不會被處理。這樣說是不是比剛才好理解一點了呢?這其實就是awk中的"模式"。
再啰嗦一遍,當awk進行逐行處理的時候,會把pattern(模式)作為條件,判斷將要被處理的行是否滿足條件,是否能跟"模式"進行匹配,如果匹配,則處理,如果不匹配,則不進行處理。
以下是AWK模式的示例 NF=2 或者 NF>2 是條件,也就是模式
[root@cnblogs ~]# awk 'NF==2 {print $0}' /etc/passwd ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin nscd:x:28:28:NSCD Daemon:/:/sbin/nologin [root@cnblogs ~]# awk 'NF>2 {print $0}' /etc/passwd systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin dbus:x:81:81:System message bus:/:/sbin/nologin polkitd:x:999:998:User for polkitd:/:/sbin/nologin
AWK支持正則表達式匹配
除此之外,還要注意以下兩點
1、當在awk命令中使用正則模式時,使用到的正則用法屬於"擴展正則表達式"。
2、當使用 {x,y} 這種次數匹配的正則表達式時,需要配合--posix選項或者--re-interval選項。
awk的"模式(Pattern)",
空模式 沒有條件,每行都處理
關系運算模式 根據條件,處理符合條件的行
BEGIN 模式
END 模式
正則模式
AWK支持"if...else if...else"這樣的"控制語句"
AWK支持for 循環,while 循環,continue,break,do ... while 循環
詳細請參考,朱雙印的博客:http://www.zsythink.net/archives/2062
#for循環語法格式1 for(初始化; 布爾表達式; 更新) { //代碼語句 } #for循環語法格式2 for(變量 in 數組) { //代碼語句 } #while循環語法 while( 布爾表達式 ) { //代碼語句 } #do...while循環語法 do { //代碼語句 }while(條件)
為了方便判斷和閱讀,最好將多個語句用{}括起來。awk分支結構允許嵌套,其格式為:
示例:
awk 'BEGIN{ test=100; if(test>90){ print "very good" } else if(test>60){ print "good" } else{ print "no pass" } }' very good
自定義變量用; 分號結尾。
while語句
示例:
awk 'BEGIN{ test=100; total=0; while(i<=test){ total+=i; i++; } print total; }' 5050
上圖中,我們使用了一個空模式,一個END模式。
如下示例,計算人名出現的次數
awk '{for (i=1;i<=NF;i++) {count[$i]++}} END{for(j in count){print j,count[j]}}' test4
以下示例得到小於100的隨機數,使用了rand() 和 srand(),int() 函數
用srand()是因為,如果只使用rand(),第一次的數值不會變化,每次都是一樣的隨機數
[root@jenkins ~]# awk 'BEGIN{srand();print rand()}' 0.0698597 [root@jenkins ~]# awk 'BEGIN{srand();print 100*rand()}' 79.413 [root@jenkins ~]# awk 'BEGIN{srand();print int(100*rand())}' 73 [root@jenkins ~]#
更多awk函數用法,請參考:
http://www.zsythink.net/archives/2113
https://www.cnblogs.com/isykw/p/6258781.html
按照列合並兩個文件
[root@cnblogs ~]# cat a 1 2 1 2 1 2 1 2 1 2 [root@cnblogs ~]# cat b 3 4 3 4 3 4 3 4 3 4 [root@cnblogs ~]# awk '{if(FNR==NR) {d[FNR]=$0}} {if(FNR!=NR){print d[FNR],$0}}' a b 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 [root@cnblogs ~]# awk '{if(FNR==NR) {d[FNR]=$1}} {if(FNR!=NR){print d[FNR],$2}}' a b 1 4 1 4 1 4 1 4 1 4 [root@cnblogs ~]# awk 'FNR==NR {x[FNR]=$0} FNR!=NR{print x[FNR],$0}' a b 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 [root@cnblogs ~]#
a和b 有相同的列,把相同的列結合在一起
[root@cnblogs ~]# cat a 116 t1 117 t2 118 t3 [root@cnblogs ~]# cat b 116 1000 117 1500 118 800 [root@cnblogs ~]# awk 'NR==FNR{a[$1]=$2}NR!=FNR{print a[$1],$2}' a b t1 1000 t2 1500 t3 800 [root@cnblogs ~]# awk '{print NR ,FNR ,$1,$2}' a b 1 1 116 t1 2 2 117 t2 3 3 118 t3 4 1 116 1000 5 2 117 1500 6 3 118 800
awk數學運算示例
求1除以3結果保留一位小數,並且用%號表示數值
[root@cnblogs ~]# t1=1 [root@cnblogs ~]# t2=3 [root@cnblogs ~]# awk 'BEGIN{printf "%.1f%\n",("'$t1'"/"'$t2'")*100}' 33.3% [root@cnblogs ~]#
awk中使用shell的環境變量
第一種方法,使用-v ,定義變量可以引用變量
[root@cnblogs ~]# abc=66666
[root@cnblogs ~]# awk -v myVAR="$abc" 'BEGIN{print myVAR}'
66666
[root@cnblogs ~]# var="test" [root@cnblogs ~]# awk -v var="$var" 'BEGIN{print var}' test
第二種方法,在awk中直接引用,使用字符串變量 ,
注意使用前格式必須是先用單引號括住再用雙引號括住,如:
"'$var'"
如果變量中含有空格或者特殊符號,需要如下
"'"$var"'"
如果不是用腳本文件方式執行,直接在shell里執行,需要先用export var=test 導出為環境變量,
這樣其后的awk子進程才會有該變量。
[root@cnblogs ~]# var="test" [root@cnblogs ~]# awk 'BEGIN{print "'$var'"}' test
[root@cnblogs ~]# var="this is a test" [root@cnblogs ~]# awk 'BEGIN{print "'"$var"'"}' this is a test [root@cnblogs ~]#
[root@cnblogs ~]# export var="this is a test" [root@cnblogs ~]# awk 'BEGIN{print "'"$var"'"}' this is a test [root@cnblogs ~]#
所有IP的連接數統計
awk 'BEGIN{while("netstat -an"|getline){if( $5 ~ /[1-255]/){split($5,t1,":");tarr[t1[1]]++;}}for(k in tarr){print k,tarr[k] | "sort -r -n -k2";}};'