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,如需轉載請自行聯系原作者