awk基本應用

一、何為awk

awk是一個強大的文本分析工具,相對于grep的查找,sed的編輯,awk明顯復雜的多也強大的多。如果雖然awk可以實現grep和sed的一些功能,但是效率卻比grep和sed慢。故如非是在show,否則建議不要使用awk去實現grep或sed的功能。在linux中awk其實是gawk,gawk是免費的!這才是重點。

二、awk語法

man下awk文檔,你會發現

NAME
       gawk - pattern scanning and processing language

SYNOPSIS
       gawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
       gawk [ POSIX or GNU style options ] [ -- ] program-text file ...

       pgawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
       pgawk [ POSIX or GNU style options ] [ -- ] program-text file ...

對于manual中的內容,可能會比較難理解,故簡化為如下格式

	awk [options] 'program' file file ...
	awk [options] 'PATTERN{action}' file file ..

常用options

-F fs                     使用‘fs’作為文本分隔符

–field-separator fs

[[email protected] tmp]$ awk -F: '/^root/{print $1,$7}' /etc/passwd
root /bin/bash

-v var=val   定義一個變量

–assign var=val

[[email protected] tmp]$ awk -v name=leon 'BEGIN{print name}'
Leon

-f program-file 從文件中讀取awk程序文件,即讀取的是'PATTERN{action}'

–file program-file

[[email protected] tmp]$ cat /tmp/awk.program 
/^root/{print $0}
/^leon/{print $0}
[[email protected] tmp]$ awk -f /tmp/awk.program /etc/passwd
root:x:0:0:root:/root:/bin/bash
leon:x:500:500:vm1:/home/leon:/bin/bash

2.1、awk的輸出

print item1, item2, …

注意事項:

(1) 各項目之間使用逗號分隔,而輸出時則使用輸出分隔符分隔;

[[email protected] tmp]$ awk -F: '/\/bin\/bash/{print $1,$7}' /etc/passwd
root /bin/bash
leon /bin/bash
mysql /bin/bash

(2) 輸出的各item可以字符串或數值、當前記錄的字段、變量或awk的表達式;數值會被隱式轉 

換為字符串后輸出;

(3) print后面item如果省略,相當于print $0;輸出空白,使用pirnt "";

[[email protected] tmp]$ awk -F: '/\/bin\/bash/{print }' /etc/passwd
root:x:0:0:root:/root:/bin/bash
leon:x:500:500:vm1:/home/leon:/bin/bash
mysql:x:495:493::/home/mysql:/bin/bash

printf format,item1,item3,…

注意事項:

(1) 要指定format;

(2) 不會自動換行;如需換行則需要給出\n

(3) format用于為后面的每個item指定其輸出格式;

format格式的指示符都%開頭,后跟一個字符:
	%c: 顯示字符的ASCII碼;
	%d, %i: 十進制整數;
	%e, %E: 科學計數法顯示數值;
	%f: 顯示浮點數;
	%g, %G: 以科學計數法格式或浮點數格式顯示數值;
	%s: 顯示字符串;
	%u: 顯示無符號整數;
	%%: 顯示%自身;
	修飾符:
	#:顯示寬度
	-:左對齊
	+:顯示數值的符號
	.#: 取值精度
	
# awk -F: '{printf "%15s %-20s\n",$1,$7}' /etc/passwd

2.2、awk的變量

2.2.1 內置變量

FS:Field Seperator, 輸入時的字段分隔符

[[email protected] tmp]$ awk 'BEGIN {FS=":"}/\/bin\/bash/{print $1,$7}' /etc/passwd
root /bin/bash
leon /bin/bash
mysql /bin/bash

RS:Record Seperator, 輸出行分隔符

[[email protected] tmp]$ awk 'BEGIN{RS=":"}{print}' /etc/passwd | head -n 10
root
x
0
0
root
/root
/bin/bash
bin
x
1

OFS: Output Field Seperator, 輸出時的字段分隔符;

[[email protected] tmp]$ awk -F: 'BEGIN{OFS="##"}/\/bin\/bash/{print $1,$7}' /etc/passwd 
root##/bin/bash
leon##/bin/bash
mysql##/bin/bash

ORS: Outpput Row Seperator, 輸出時的行分隔符;

[[email protected] tmp]$ awk -F: 'BEGIN{ORS="##"}/\/bin\/bash/{print $1,$7}' /etc/passwd 
root /bin/bash##leon /bin/bash##mysql /bin/bash##

NF:Numbers of Field,字段數

[[email protected] tmp]$ awk -F: 'END{print NF}' /etc/passwd
7

NR:Numbers of Record, 行數;所有文件的一并計數;

[[email protected] tmp]$ sudo awk -F: '{print NR}' /etc/passwd /etc/shadow
1
2
...
74
75
76

FNR:行數;各文件分別計數;

[[email protected] tmp]$ sudo awk -F: '{print FNR}' /etc/passwd /etc/shadow
1
2
3
...
36
37
38
1
2
3
...

ARGV:數組,保存命令本身這個字符,awk '{print $0}' 1.txt 2.txt,意味著ARGV[0]保存 

[[email protected] tmp]$ awk 'END{print ARGV[0]}' /etc/passwd
awk

ARGC: 保存awk命令中參數的個數;

FILENAME: awk正在處理的當前文件的名稱;

[[email protected] tmp]$ awk 'END{print FILENAME}' /etc/passwd
/etc/passwd

2.2.2 自定義變量 

#awk -v name=leon 'BEGIN{print name}'
# awk 'BEGIN{name="leon";print name}'

2.3、 awk輸出重定向

print items > output-file
print items >> output-file
print items | command
# awk -F: '{print $1,$7 >"/tmp/userAndBash.txt"}' /etc/passwd

2.4、 awk操作符

幾個就沒什么好說的了,算術操作符,賦值操作符,比較操作符,邏輯操作符等都支持

三元條件表達式

selector?if-true-expression:if-false-expression
# awk -F: '{$3>=500?utype="common user":utype="admin or system user";print $1,"is",utype}' /etc/passwd

2.5、 模式 PATTREN

2.5.1 Regexp: 格式為/PATTERN/

僅處理被/PATTERN/匹配到的行;

[[email protected] ~]$ awk -F: '/^root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

2.5.2 Expression: 表達式

其結果為非0或非空字符串時滿足條件,僅處理滿足條件的行;

[[email protected] tmp]$ awk -F: '$3>=500{print $1,$3,$7}' /etc/passwd
leon 500 /bin/bash
nfsnobody 65534 /sbin/nologin

2.5.3 Ranges: 行范圍

此前地址定界,startline, endline,僅處理范圍內的行

[[email protected] ~]$ awk -F: '/^root/,/^daemon/{print $1,$7}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin

2.5.4 BEGIN/END: 特殊模式

僅在awk命令的program運行之前(BEGIN)或運行之后 ,(END)執行一次;

[[email protected] ~]$ sudo awk --re-interval  -F: 'BEGIN{print "--there users  have a passwd--"}/\$1/{print $1}END{print "----end---"}' /etc/shadow
--there users  have a passwd--
root
leon
----end---

2.5.5 Empty:空模式

匹配任意行;這里就不舉例子了

2.6、常用的action

 (1) expressions  :表達式

 (2)control statements    :控制語句

 (3)compound statements    :組合語句

 (4)input statements    :輸入語句

 (5) output statements    :輸出語句

2.7、控制語句

2.7.1 if-else

格式:if (condition) {body} else {body}

[[email protected] ~]$ awk -F: '{if ($3>=500) {print $1,"is a common user"} else {print  $1, "is an admin or system user"}}' /etc/passwd
root is an admin or system user
bin is an admin or system user
...
[[email protected] ~]$ awk -F: '{if (NF>=3){print $0}}' /etc/inittab
id:3:initdefault:

2.7.2 while

格式:while (condition) {while body}

# awk '{i=1; while (i<=NF){printf "%s ",$i;i+=2};print ""}'  /etc/inittab
# awk '{i=1; while (i<=NF){if (length($i)>=6) {print $i}; i++}}' /etc/inittab
length()函數:取字符串的長度

2.7.3 do-while循環

格式:do {body} while (condition)

跟上面例子類似,只不過do中的內容無論如何都會執行一次,不舉例

2.7.4 for循環

格式:for (variable assignment; condition; iteration process) {body}

# awk '{for (i=1;i<=NF;i+=2){printf "%s ",$i};print ""}'  /etc/inittab
# awk '{for (i=1;i<=NF;i++){if (length($i)>=6) print $i}}'  /etc/inittab

for循環可用來遍歷數組元素:

語法:for (i in array) {body}

awk '{ip[$1]++}END{for (i in ip) {print i,ip[i]}}' /var/log/httpd/access_log

2.7.5 case語句

語法:switch (expression) {case VALUE or /RGEEXP/: statement1;…  default: stementN}

2.7.6 循環控制

break               #跳出當前循環 
continue            #直接進入下一循環

2.7.7 next

提前結束對本行的處理進而進入下一行的處理;

# awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd
# awk -F: '{if(NR%2==0) next; print NR,$1}' /etc/passwd

2.8、 數組

array[index-expression]

index-expression :可以使用任意字符串,如果某數組元素在引用時事先不存在,那么在引用時,awk會自動創建此元素并將其賦值為空串;因此要判斷數組中是否存在某元素,使用index in array這個格式

要遍歷數組中的每一個元素,需要使用以下特殊結構

for (var in array_name) {for body}

其var會遍歷array的索引

# awk '{ip[$1]++}END{for (i in ip) {print i,ip[i]}}' /var/log/httpd/access_log

刪除數組元素:

delete array[index]

2.9、 awk函數

2.9.1 內置函數

 split(string,array[,fieldsep[,seps]])

 功能:將string表示的字符串以fieldsep為分隔符進行切片,并切片后的結果保存至array為名的數組中;數組小標從1開始

awk 'BEGIN {split("root:x:0:0",user,":");for (i in user) print user[i]}'

此函數有返回值,返回值為切片后的元素的個數

# netstat -tn | awk '/^tcp/{lens=split($5,client,":");ip[client[lens-1]]++}END{for (i in ip) print i,ip[i]}'

length(string)

功能:返回給定字串的長度

# awk '{for (i=1;i<=NF;i++){if (length($i)>=6) print $i}}'  /etc/inittab

substr(string,start[,length])

功能:從string中取子串,從start為起始位置為取length長度的子串;

2.9.2 自定義函數

function  function_name(arg1,arg2,….) {body}

函數調用: function_name(arg1,arg2,…)

[[email protected] tmp]$ echo "3 2" | awk 'function compare(a,b){if(a>b) {return a} else {return b}};{print compare($1,$2)}' 
3

三、總結

作為三劍客之一,awk經常被使用,特別需要注意awk的語法。如,不要把BEGIN和ENG執行的內容當成PATTERN{action},而應該是program,同時function函數也是如此,當成program,否則一不留神就寫成'{function function_name(arg…) {body}}'。犯了語法錯誤。

原創文章,作者:成吉思汗,如若轉載,請注明出處:http://www.npownk.tw/9291

評論列表(1條)

  • stanley
    stanley 2015-11-18 11:06

    果斷置頂,以前也做過awk的技能分享,時間長也忘的差不多了。加油!

聯系我們

400-080-6560

在線咨詢

工作時間:周一至周五,9:30-18:30,節假日同時也值班

QR code
安徽十一选五分布走势