天天看點

shell 正則表達三劍客--awk

awk指令

awk和sed一樣是流式編輯器,它也是針對文檔中的行來操作的,一行一行的去執行。awk比sed更加強大,它能做到sed能做到的。awk工具其實是很複雜的,有專門的書籍來介紹它的使用。

1 awk指令形式

awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file

 [-F|-f|-v]   大參數,-F指定分隔符,-f調用腳本,-v定義變量 var=value

'  '         引用代碼塊

BEGIN       初始化代碼塊,主要是引用全局變量,設定FS分隔符

//           比對代碼塊,可以是字元串或正規表達式

{}           指令代碼塊,包含一條或多條指令

;          多條指令使用分号分隔

END          結尾代碼塊,主要是進行最終計算或輸出結尾摘要資訊

2 特殊變量符

$0           表示整個目前行

$1           每行第一個字段

NF           字段數量變量

NR           每行的記錄号,多檔案記錄遞增

FNR          與NR類似,不過多檔案記錄不遞增,每個檔案都從1開始

\t           制表符

\n           換行符

FS           BEGIN時定義分隔符

RS           輸入的記錄分隔符, 預設為換行符(即文本是按一行一行輸入)

~            比對,與==相比不是精确比較

!~           不比對,不精确比較

==           等于,必須全部相等,精确比較

!=           不等于,精确比較

&&           邏輯與

||           邏輯或

+            比對時表示1個或1個以上

/[0-9][0-9]+/    兩個或兩個以上數字

/[0-9][0-9]*/    一個或一個以上數字

FILENAME 檔案名

OFS          輸出字段分隔符, 預設也是空格,可以改為制表符等

ORS          輸出的記錄分隔符,預設為換行符,即處理結果也是一行一行輸出到螢幕

-F'[:#/]'      定義三個分隔符

3 執行個體解析

截取文檔中的某個段

[root@localhost ~]# head -n2 /etc/passwd |awk -F ':' '{print $1}'

root

bin

解釋一下,-F 選項的作用是指定分隔符,如果不加-F指定,則以空格或者tab為分隔符。 Print為列印的動作,用來列印出某個字段。$1為第一個字段,$2為第二個字段,依次類推,$0表示整行。

[root@localhost ~]# head -n2 test.txt |awk -F':' '{print $0}'

rto:x:0:0:/rto:/bin/bash

operator:x:11:0:operator:/roto:/sbin/nologin

注意awk的格式,-F後緊跟單引号,然後裡面為分隔符,print的動作要用 { } 括起來,否則會報錯。print還可以列印自定義的内容,但是自定義的内容要用雙引号括起來。

[root@localhost ~]# head -n2 test.txt |awk -F':' '{print $1"#"$2"#"$3"#"$4}'

rto#x#0#0

operator#x#11#0

比對字元或字元串

[root@localhost ~]# awk '/oo/' test.txt

operator:x:11:0:operator:/rooto:/sbin/nologin

roooto:x:0:0:/rooooto:/bin/bash

[root@localhost ~]# awk -F ':' '$1 ~/oo/' test.txt

可以讓某個段去比對,這裡的’~’就是比對的意思

[root@localhost ~]# awk -F ':' '/root/ {print $1,$3} /test/ {print $1,$3}' /etc/passwd

root 0

operator 11

test 511

test1 512

awk還可以多次比對,如上例中比對完root,再比對test,它還可以隻列印所比對的段。

條件操作符

[root@localhost ~]# awk -F ':' '$3=="0"' /etc/passwd

root:x:0:0:root:/root:/bin/bash

awk中是可以用邏輯符号判斷的,比如 ‘==’ 就是等于,也可以了解為 ‘精确比對’ 另外也有 >, ‘>=, ‘<, ‘<=, ‘!= 等等,值得注意的是,在和數字比較時,若把比較的數字用雙引号引起來後,那麼awk不會認為是數字,而認為是字元,不加雙引号則認為是數字。

[root@localhost ~]# awk -F ':' '$3>="500"' /etc/passwd

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

halt:x:7:0:halt:/sbin:/sbin/halt

mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

nobody:x:99:99:Nobody:/:/sbin/nologin

dbus:x:81:81:System message bus:/:/sbin/nologin

vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin

haldaemon:x:68:68:HAL daemon:/:/sbin/nologin

postfix:x:89:89::/var/spool/postfix:/sbin/nologin

sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin

tcpdump:x:72:72::/:/sbin/nologin

user11:x:510:502:user11,user11's office,12345678,123456789:/home/user11:/sbin/nologin

test:x:511:511::/home/test:/bin/bash

test1:x:512:511::/home/test1:/bin/bash

在上面的例子中,要把uid大于等于500的行列印出,但是結果并不是我們的預期,這是因為awk把所有的數字當作字元來對待了

[root@localhost ~]# awk -F ':' '$7!="/sbin/nologin"' /etc/passwd

sync:x:5:0:sync:/sbin:/bin/sync

!= 為不比對,除了針對某一個段的字元進行邏輯比較外,還可以兩個段之間進行邏輯比較。

[root@localhost ~]# awk -F ':' '$3<$4' /etc/passwd

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

games:x:12:100:games:/usr/games:/sbin/nologin

gopher:x:13:30:gopher:/var/gopher:/sbin/nologin

ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

另外還可以使用 && 和 || 表示 “并且” 和 “或者” 的意思。

[root@localhost ~]# awk -F ':' '$3>"5" && $3<"7"' /etc/passwd

[root@localhost ~]# awk -F ':' '$3>"5" || $7=="/bin/bash"' /etc/passwd

awk常用的變量

NF :用分隔符分隔後一共有多少段

NR :行數

[root@localhost ~]# head -n3 /etc/passwd | awk -F ':' '{print NF}'

7

[root@localhost ~]# head -n3 /etc/passwd | awk -F ':' '{print $NF}'

/bin/bash

/sbin/nologin

NF 是多少段,而$NF是最後一段的值, 而NR則是行号。

[root@localhost ~]# head -n3 /etc/passwd | awk -F ':' '{print NR}'

1

2

3

我們可以使用行号作為判斷條件:

[root@localhost ~]# awk 'NR>20' /etc/passwd

abrt:x:173:173::/etc/abrt:/sbin/nologin

也可以配合段比對一起使用:

[root@localhost ~]# awk -F ':' 'NR>20 && $1 ~ /ssh/' /etc/passwd

awk可以把段值更改

[root@localhost ~]# head -n 3 /etc/passwd |awk -F ':' '$1="root"'

root x 0 0 root /root /bin/bash

root x 1 1 bin /bin /sbin/nologin

root x 2 2 daemon /sbin /sbin/nologin

awk還可以對各個段的值進行數學運算

[root@localhost ~]# head -n2 /etc/passwd

bin:x:1:1:bin:/bin:/sbin/nologin

[root@localhost ~]# head -n2 /etc/passwd |awk -F ':' '{$7=$3+$4}'

[root@localhost ~]# head -n2 /etc/passwd |awk -F ':' '{$7=$3+$4; print $0}'

root x 0 0 root /root 0

bin x 1 1 bin /bin 2

當然還可以計算某個段的總和

[root@localhost ~]# awk -F ':' '{(tot=tot+$3)}; END {print tot}' /etc/passwd

2891

這裡的END要注意一下,表示所有的行都已經執行

[root@localhost ~]# awk -F ':' '{if ($1=="root") print $0}' /etc/passwd

日常應用

應用1

awk -F: '{print NF}' helloworld.sh          輸出檔案每行有多少字段

awk -F: '{print $1,$2,$3,$4,$5}' helloworld.sh  輸出前5個字段

awk -F: '{print $1,$2,$3,$4,$5}' OFS='\t' helloworld.sh 輸出前5個字段并使用制表符分隔輸出

awk -F: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh 制表符分隔前5個字段,并列印行号

應用2

awk -F'[:#]' '{print NF}'  helloworld.sh     指定多個分隔符: #,輸出每行多少字段

awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh  制表符分隔輸出多字段

應用3

awk -F'[:#/]' '{print NF}' helloworld.sh      指定三個分隔符,并輸出每行字段數

awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6}' helloworld.sh  制表符分隔輸出多字段

應用4

計算/home目錄下,普通檔案的大小,使用KB作為機關,int是取整的意思

ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}'

ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'     應用5

統計netstat -anp 狀态為LISTEN和CONNECT的連接配接數量分别是多少

netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'

應用6

統計/home目錄下不同使用者的普通檔案的總數是多少

ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'   

mysql        199 

root         568

統計/home目錄下不同使用者的普通檔案的大小總size是多少

ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'

本文轉自super李導51CTO部落格,原文連結: http://blog.51cto.com/superleedo/1888014,如需轉載請自行聯系原作者