一、awk簡介
awk的意思是報告生成器,能根據輸入信息,把信息格式化後顯示,繼而出現new awk(nawk)在windows上實現,gawk,awk實現在linux上。awk是一種編程語言,在linux/unix下對文本和數據進行處理,是一款強大編程工具。在命令行中使用,更多作爲腳本來使用。
awk處理文件和數據的方式:逐行掃描文件,從第一行到最後一行,尋找匹配的特定模式的行,並在這些行上進行操作。如果沒有指定處理動作,則把匹配行打印,如果沒有指定模式,則所有行都處理。gawk是awk的GNU版本。可通過命令ll `which awk`查看
Linux文本處理三劍客:
grep, egrep, fgrep: 文本過濾器
sed: 文本編輯(行編輯器)
awk: 文本格式化,報表生成器
awk工作過程
根據定義的模式,一次從文本中讀取一行,awk會對行做相應的切片,將每一行按照分割符進行切割。例如this is a test 使用空白字符做分隔符將它們分開,切割爲this,is,a,test四個片,可以使用變量,分別對應爲$1,$2,$3,$4代表四個切割片
二、awk用法
1、基本格式
gawk [options] 'program' file file ...
program程序: PATTERN { ACTION STATEMENT }
由語句組成,語句分隔符是";"
ACTION: print, printf
選項options:
-F[]:指明輸入字段分隔符;默認以空白爲分隔符
-F[, ]:逗號或空格爲分隔符
-v var=val: 變量賦值,無須聲明,可直接調用
-f /path/from/awk_script
EX:
(1)、打印/etc/passwd中的第三行和第六行不同用法
#awk -F: '{print $3,$6}' /etc/passwd #awk -F: -v f1=3 -v f2=6 '{print $f1,$f2}' /etc/passwd #awk -v FS=':' '{print $3,$6}' /etc/passwd
(2)、運行awk腳本
#vim awk.script {print $1,$3} #awk -f awk.script -F: /etc/passwd
2、awk的輸出命令print
print item1, item2, ...
item:
(1)字符串:用引導引用
print "htello","world"
(2)變量:顯示變量的值
print name
要點:
(1)item間用逗號,輸出爲空白字符
(2)item可以爲字符串、變量、數值等
(3)item如果省略,等於print $0
(4)輸出空白字符,print ""
EX:打印/etc/passwd中的所有用戶
#awk -F: '{print "user is",$1}' /etc/passwd
3、變量
3.1 內置變量
(1)FS: input field seperator,輸入字段分隔符,默認爲空白字符;
#awk -v FS=":" '{print $1,$3}' /etc/passwd #vim awk.txt This is the first line. Here you are. This is tomas,jason. #awk '{print $3}' awk.txt #awk -v FS="[ ,]" '{print $3}' awk.txt //輸出以逗號或空白字符爲分隔符的字段
(2)RS:input record separator,輸入行分隔符 默認爲換行符;
#awk -v RS=" " '{print $0}' /etc/passwd
(3)OFS: output field separator,輸出字段分隔符,默認爲空白字符;
#awk -v FS=":" -v OFS=":" '{print $1,$3,$7}' /etc/passwd //輸出字段分隔符也爲":"
(4)ORS:output record separator,輸出行分隔符, 默認爲換行符;
#awk -v RS=" " -v ORS=" " '{print $0}' /etc/passwd
(5)NF: number of field in current record,當前行的字段數;
#awk '{print NF}' /etc/issue //打印行數 #awk '{print $NF}' /etc/issue //打印行最後字段
(6)NR:行數,所有文件統一計數;
#awk '{print NR}' /etc/issue
(7)FNR:行數,各文件分別計數;
#awk '{print FNR}' /etc/fstab /etc/issue
(8)FILENAME:當前被讀取的文件名
#awk '{print NR,FILENAME}' /etc/issue
(9)ARGC:命令行參數的個數;
#awk '{print ARGC}' /etc/issue //這裏顯示爲兩個參數,包括print和文件名
(10)ARGV:數組,保存了命令行參數自身
#awk '{print ARGV[0]}' /etc/issue //參數爲print和文件名,但是輸出ARGV[0],則顯示爲awk
3.2 自定義變量
-v var=val:
變量名命名規則:
區分字符大小寫
數字,字符,下劃線,不能以數字開頭
不能使用內置關鍵字
定義變量的位置:
(1) 可以program中定義變量;
(2) 通過-v選項定義變量;
#awk 'BEGIN{FS=":";f1=1}{print $f1}' /etc/passwd //只在開始賦值一次 #awk -F: '{f1=1;print $f1}' /etc/passwd //每行都要賦值
4、printf命令
格式: printf format, item1, item2, ...
(1)要點:
(1) format是必須的;
(2) 不自動換行,需給換行符;\n
(3) 爲每個item指定格式符;否則item無法顯示
(2)格式符:都以%開頭,後跟一個字符
%c: 顯示字符的ASCII碼;
%d,%i: 顯示十進制整數;
%e, %E: 科學計數法顯示數值;
%f: 顯示爲浮點數;
%g, %G: 以科學計數法格式或浮點數格式顯示數值;
%s: 字符串
%u: 無符號的整數
%%: 顯示%自身
#awk -F: '{printf "This is user: %s.\n",$1}' /etc/passwd #awk -F: '{printf "This is user: %s,his UID is %d.\n",$1,$3}' /etc/passwd
(3)修飾符:
#[.#]: 第一個#指定顯示寬度,例如%30s;第二個#表示小數點後的精度;
-: 左對齊,默認爲右對齊
+:顯示數值符號
#awk -F: '{printf "This is user: %s,his UID is %-20f.\n",$1,$3}' /etc/passwd //UID顯示爲20個字符並且精度爲2 #awk -F: '{printf "%20s:%-d\n",$1,$3}' /etc/passwd
5、操作符:
(1)算術操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x: 負值
+x: 轉換爲數值
#awk 'BEGIN{print 4*5}'
(2)字符串操作:字符串連接
#awk ‘BEGIN{print "hello" "awk"}’
(3)賦值操作符:
=, +=, -=, *=, /=, %=, ^=
++, --
#awk -v f1=3 'BEGIN{f1*=6;print f1}'
(4)比較操作符:
>, >=, <. <=, ==, !=
(5)模式匹配符:
~:能匹配爲真
!~:不能匹配爲真
(6)邏輯操作符:
&& 與運算
|| 或運算
(7)條件表達式:
selector?if-true-expression:if-false-expression
相當於bash的:
if SELECTOR;then
if-true-expression
else
if-false-expression
# awk -F: '{$3>=500?usertype="common user":usertype="sysuser or admin";printf "%20s:%-s\n",$1,usertype}' /etc/passwd #df -h | awk '{printf "%30s:%-s\n",$1,$5}'
(8)函數調用:
function_name(argu1,argu2,...)
6、PATTERN
(1) /regular expression/: 正則表達式,僅處理能夠被/regular expression/所匹配到的行;
#awk -F: '/^[ab]/{print $1,$3}' /etc/passwd
(2) relational expression:關係表達式,有真假之分,一般來說,其結果爲非0或非空字符串時爲“真”,否則,爲“假”;
#awk -F: '$3>=500{print $1,$3}' /etc/passwd //打印UID大於和等於500的用戶名和UID #awk -F: '$1~/root/{print $1,$3}' /etc/passwd //打印用戶名包含root的用戶名和UID
(3) line ranges:行範圍,類似sed或vim的地址定界法;startline, endline
(4) BEGIN/END: 特殊模式
BEGIN:程序執行前執行一次
END:程序執行後執行一次
#awk -F: 'BEGIN{printf "%20s:%-s\n","UserName","UserID"}{printf "%20s:%-d\n",$1,$3}END{print "--------\nprogram is end"}' /etc/passwd #awk 'BEGIN{FS=":"}{print $1,$3}' /etc/passwd
(5) empty: 空模式,匹配任意行;
#awk -F: '{print $1,$NF}' /etc/passwd
7、常用的action
(1) Expressions 表達式,如變量賦值
(2) Control statements 控制語句,如if,while等
(3) Compound statements 複合語句,如{}
(4) input statements 輸入語句
(5) output statements 輸出語句
8、控制語句
if (condition條件) { statement語句 } [ else statement ]
while (condition) { statement }
do statement while (condition)
for (expr1初值; expr2循環; expr3修正) statement
for (var in array) statement
switch (expression) {case VALUE or /REGEXP/:statement;...;default;statement}
break 結束循環
continue 結束本輪循環
delete array[index]
delete array
exit [ expression ]
{ statements }
8.1 if-else
語法:if (condition條件) statement [ else statement ]
if (condition) { statements; } [ else { statements; }]
# awk -F: '{if ($3>=500) print $1," is a common user." }' /etc/passwd # awk -F: '{if ($3>=500) {print $1," is a common user."} else {print $1," is a system user or admin."}}' /etc/passwd # awk '{if (NF>6) print NF, $0 }' /etc/inittab
用法:對awk取得的整行或行中的字段做條件判斷;
8.2 while循環
語法:while (condition) statement
while (condition) { statements }
條件爲真時進行循環,直到爲假退出;
用法:通常用於在當前行的各字段間進行循環;
# awk '{i=1;while(i<=NF){printf "%20s:%d\n",$i,length($i); i++}}' /etc/inittab //打印每行字段名稱和字段長度 # awk '{i=1;while(i<=NF){if (length($i)>5) {printf "%20s:%d\n",$i,length($i);} i++}}' /etc/inittab //查找打印在文件/etc/inittab下每行字段長度大於5的字段名稱和長度
8.3 do-while循環 瞭解
語法:do statement while (condition)
do { do-while-body } while (condition)
意義:至少執行一次循環體;
8.4 for循環
語法:for (expr1; expr2; expr3) statement
for (expr1; expr2; expr3) { statements }
for (varaiable assignment; condition; iteration process) { for-body }
#awk '{for(i=1;i<=NF;i++){if(length($i)>=6) print $i}}' /etc/issue //查找文件/etc/issue字段長度大於等於6並打印字段 #awk '{for(i=1;i<=NF;i++) {printf "%s:%d\n", $i, length($i)}}' /etc/inittab
for循環在awk中有一個專用於遍歷數組元素:
語法:for (var in array) { for-body }
8.5 switch 瞭解
語法:switch (expression) {case VALUE or /REGEXP/: statement; ...; default: statementN}
8.6 break and continue
break [n]: 退出當前循環,n表示幾層循環
continue:提前結束本輪循環,直接進入下輪循環
8.7 next
提前結束對本行的處理而進入下一行的處理
# awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd //打印UID爲奇數的行的1和3字段,對UID取模,如果等於0則執行next進入對下一行的處理,如果不等於0則執行一條語句打印$1和$3字段
9、Array 數組
關聯數組:array[index-expression]
index-expression: 索引表達式
可以使用任意字符串;
如果某數組元素事先不存在,在引用時,awk會自動創建此元素並將其值初始化爲空串;
因此,若要判斷數組是否存在某元素,要使用“index in array”進行;
要遍歷數組中的每個元素,要使用: for (var in array) ,var會遍歷array的每個索引,所以,要顯示數組元素的值,要使用array[var]
weekdays
weekdays[mon]="Monday"
weekdays[tue]="tuesday"
...
for(i in weekdays) 此時i會遍歷weekdays數組的每個索引,即mon,tue,而非元素的值"Monday"或"Tuesday"等
要獲取元素的值:weekdays[i]
EX:統計每一行中各單詞分別出現的次數
可定義一個數組,用單詞本身當索引,而元素的值存儲單詞出現的次數
# awk '{for(i=1;i<=NF;i++) {count[$i]++}}END{for(j in count) {print j,count[j]}}' awk.txt //統計文本中每個單詞及出現的次數,第一個for定義數組,第二個for遍歷數組 # awk '{for(i=1;i<=NF;i++) {count[$i]++}}END{for(j in count) {print j,count[j]};delete count}' awk.txt //分別統計每行每個單詞及出現的次數 # ss -tan | awk '!/^State/{state[$1]++}END{for (i in state) {print i,state[i]}}' //統計TCP連接各狀態名稱及個數 #awk '{ip[$1]++}END{for(i in ip)print i,ip[i]}' /var/log/httpd/access_log //統計web被訪問的IP及次數 # netstat -tan | awk '/^tcp/{state[$NF]++}END{for(i in state){print i,state[i]}}
10、函數
(1)內置函數
1)數值處理:
rand(): 返回0和1之間一個隨機數;
#awk 'BEGIN{print rand()}'
2)字符串處理:
ength([s]): 返回指定字符串的長度
#awk 'BEGIN{print length("hello")}'
3)sub(r, s [, t])查找r在t中,把每行第一次出現的r替換爲s
sub(ab,AB,$0)
#vim count.txt How are you? How old are you? #awk '{sub("are","ARE",$0);print $0}' count.txt
4)gsub(r, s [, t]):查找r在t中,把所有出現的r替換爲s
5)split(s, a [, r]): 以r爲分隔符,s爲字符串切割,並把結果保存到a中
注意:awk的數組下標從1開始編號
#awk '{split($0,userinfo,":");print userinfo[1]}' /etc/passwd //以":"爲分隔符,$0爲字符串切割,並把結果保存到userinfo中 # netstat -tan | awk '/^tcp/{len=split($5,client,":");ip[client[len-1]]++}END{for(i in ip){print i,ip[i]}}'
6)substr(s, i [, n]): 從s表示的字符串中取子串,從i開始,取n個字符;
7)時間類的函數:
systime(): 取時間戳;
8)位運算函數:
and(v1,va2):
(2)自定義函數
function f_name(p,q)
{
...
}