本質: 是一門編程語言,有自己的語法和庫函數。 工作機理: 讀取每一行 按分隔符把這一行切成多個(不指定分隔符的話,空白或者連續空白就是分隔符) $1:代表第一列;$2:第二列。。。。 $0:整行內容 按需,按特定格式列印出來 功能: 可以限定處理哪些行 可以根據列的內容做條件分支處理 可以迴圈所有 ...
本質:
是一門編程語言,有自己的語法和庫函數。
工作機理:
讀取每一行
按分隔符把這一行切成多個(不指定分隔符的話,空白或者連續空白就是分隔符)
$1:代表第一列;$2:第二列。。。。
$0:整行內容
按需,按特定格式列印出來
功能:
- 可以限定處理哪些行
- 可以根據列的內容做條件分支處理
- 可以迴圈所有列
- 可以自己定義變數
命令基本用法:
awk [option] 'PROGRAM' FILE...
PROGRAME:PATERN{ACTION STATEMENTS}
例子1:/etc/fstab文件用空白分隔,列印出第二列和第四列。
列之間用逗號分隔,列印出來的列之間就有空格;不加逗號,就把這2列連一起了
[root@localhost ~]# tail -4 /etc/fstab
/dev/mapper/centos-root / xfs defaults 0 0
UUID=3d3b316a-529e-484a-9895-e785fdde5365 /boot xfs defaul
/dev/mapper/centos-home /home xfs defaults 0 0
/dev/mapper/centos-swap swap swap defaults 0 0
[root@localhost ~]# tail -4 /etc/fstab | awk '{print $2,$4}'
/ defaults
/boot defaults
/home defaults
swap defaults
[root@localhost ~]# tail -4 /etc/fstab | awk '{print $2 $4}'
/defaults
/bootdefaults
/homedefaults
swapdefaults
例子2:/etc/fstab文件用空白分隔,列印出第二列和第四列,並隨意加幾列
# tail -4 /etc/fstab | awk '{print "hi",$2,$4,567}'
hi / defaults 567
hi /boot defaults 567
hi /home defaults 567
hi swap defaults 567
由上面2個小例子,可以看出awk的基本使用要點:
- print的項目間,加了逗號,列印出來的項目之間就有空格
- print後面的內容,可以是列號,自己定義的變數,隨意的字元串和數字
- print後面如果省略項目,就是列印$0
選項
- -F:告訴awk用什麼分隔符,去分隔輸入
- -v:自定義變數。var=value。定義多個變數要使用多次-v
awk的變數
1,內置變數
FS:input file seperator 輸入列分隔符,預設是空白或者連續空白
# tail -4 /etc/fstab | awk -v OFS=',' '{print $3,$4}' xfs,defaults xfs,defaults xfs,defaults swap,defaults
OFS:output file seperator 輸出列分隔符,預設是空白或者連續空白
# tail -4 /etc/passwd | awk -v FS=':' '{print $1,$4}' us3 1002 user100 1003 user101 1004 apache 48
# tail -4 /etc/passwd | awk -v FS=':' -v OFS=':' '{print $1,$4}'
us3:1002
user100:1003
user101:1004
apache:48
RS:input record seperator 輸入行識別符,預設是回車
ORS:output record seperator 輸出行識別符,預設是回車
NF:每行里列的數量
在awk內部引用變數不需要加$。
# awk '{print NF}' /etc/fstab 0 1 2 10 1 9 12 1 6 6 6 6
NR:文件的行號
# awk '{print NR}' /etc/fstab 1 2 3 4 5 6 7 8 9 10 11 12
如果是多個文件,則連續計數行號。
# awk '{print NR}' /etc/fstab /etc/issue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
FNR:如果是多個文件,則單獨計數行號。
# awk '{print FNR}' /etc/fstab /etc/issue 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3
FILENAME:顯示文件名
# awk '{print FILENAME}' /etc/fstab /etc/issue /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/issue /etc/issue /etc/issue
ARGC:命令行參數的個數
ARGV:數組,保存的是接收到的命令行參數。
# awk '{print ARGC, ARGV[0],ARGV[1],ARGV[2]}' /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue # awk 'BEGIN{print ARGC, ARGV[0],ARGV[1],ARGV[2]}' /etc/fstab /etc/issue 3 awk /etc/fstab /etc/issue
2,自定義變數
變數名區分大小寫,可以使用-v定義;也可以在PROGRAM體里定義。什麼是PROGRAM,在大括弧里的部分。PROGRAME里的多個語句,使用分號分隔。
使用-v定義變數
# awk -v var="122dd" '{print var}' /etc/issue 122dd 122dd 122dd
在在PROGRAM體里定義變數
# awk '{var="11d";print var}' /etc/issue 11d 11d 11d
printf語句用法
實現格式化輸出。不自動換行,使用\n是換行。
格式符:
- %c:顯示ascii碼
- %d,%i:顯示十進位整數
- %e, %E:顯示科學計數法
- %f:顯示浮點數
- %g, %G:顯示科學計數法或浮點數
- %s:顯示字元串
- %u:顯示無符號整數
- %%:顯示%自身
# awk -F: '{printf "username:%s,uid:%d\n",$1,$3}' /etc/passwd
username:avahi,uid:70
username:postfix,uid:89
修飾符:
- 數字1[.數字2]
- -數字1[.數字2]:左對齊
- +數字1[.數字2]:顯示數字的符號,正數顯示+,符號顯示-
數字1:顯示時,列所占用的寬度。預設是右對齊,-號是左對齊。
數字2:有小數點的話,指定顯示幾位小數。
# awk -F: '{printf "username:%15s,uid:%d\n",$1,$3}' /etc/passwd
username: user101,uid:1004
username: apache,uid:48
# awk -F: '{printf "username:%-15s,uid:%d\n",$1,$3}' /etc/passwd
username:user100 ,uid:1003
username:user101 ,uid:1004
username:apache ,uid:48
操作符
1,算術操作符
a+b,a-b,a*b,a/b,a^b,a%b,
2,字元串操作符
沒有操作符,就是連接字元串
3,賦值操作符
=,+=,-=,*=,/=,%=,^=
++,--
4,比較操作符
>,>=,<,<=,!=,==
5,模式匹配符
~:左側的字元串是否能被右側的模式所匹配
!~:左側的字元串是否能被右側的模式所不匹配
6,邏輯操作符
&&,||,!
7,函數調用
function_name(arg1,arg2...)
8,條件表達式
selector?true:false
例子:uid大於等於1000的是aa。
# awk -F: '{$3>=1000?ut="aa":ut="bb"; printf "%s:%d\n", ut, $3}'\n /etc/passwd
PATTERN
選擇要處理的行,不寫pattern預設是處理所有行。
1,/正則表達式/:僅把被匹配到的行作為處理對象
僅處理UUID開頭的行
# awk -F' ' '/^UUID/{print $1, $3}'\n /etc/fstab
UUID=3d3b316a-529e-484a-9895-e785fdde5365 xfs
a僅處理不以UUID開頭的行
# awk -F' ' '!/^UUID/{print $1, $3}'\n /etc/fstab
#
#
# by
#
# filesystems,
# man
#
/dev/mapper/centos-root xfs
/dev/mapper/centos-home xfs
/dev/mapper/centos-swap swap
2,關係表達式:結果為真的行,才是處理對象。結果是非0或非空白都是真。
處理uid大於等於1000的行
# awk -F: '$3>=1000{print $1,$3}' /etc/passwd
nfsnobody 65534
us1 1001
us3 1002
user100 1003
user101 1004
處理shell是bash的行
最後一列的字元串包含bash的行
# awk -F: '$NF~"bash"{print $1,$NF}' /etc/passwd
root /bin/bash
ys /bin/bash
us1 /bin/bash
us3 /bin/bash
user100 /bin/bash
user101 /bin/bash
最後一列的字元串以bash結尾的行
# awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd
root /bin/bash
ys /bin/bash
us1 /bin/bash
us3 /bin/bash
user100 /bin/bash
user101 /bin/bash
# awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
root /bin/bash
ys /bin/bash
us1 /bin/bash
us3 /bin/bash
user100 /bin/bash
user101 /bin/bash
指定處理的行號
# awk -F: 'NR>=1&&NR<=3{print $1,$NF}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
指定處理的開始行,終了行,但不是用數字,而是用pattern
# awk -F: '/^root/,/^daemon/{print $1,$NF}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
3,BEGIN,END
- BEGIN:處理第一行前,執行一次BEGIN。一般用於列印表頭。
- END:處理完最後一行後,執行一次END。一般用於列印彙總。
# awk -F: 'BEGIN{print " username uid"} {print $1,$3}' /etc/passwd
username uid
root 0
bin 1
daemon 2
列印出前5行的username和uid,併在結尾統計出:uid之和
# awk -F: -v sum=0 'BEGIN{print "username uid"} NR>=1&&NR<=5{printf "%8s %3d\n", $1,$3;sum+=$3} END{printf " sum:%s\n",sum}' /etc/passwd
username uid
root 0
bin 1
daemon 2
adm 3
lp 4
sum:10
常用的action
1,控制語句
if(condition) {...}
僅顯示uid大於等於1000的行。
# awk -F: '{ if($3>=1000) {print $1,$3}}' /etc/passwd nfsnobody 65534 ys 1000 us1 1001 us3 1002 user100 1003 user101 1004
if(condition) {...} else {...}
# awk -F: '{ if($3>=1000) {printf "user:%s\n",$1} else {printf "suser:%s\n",$1} }' /etc/passwd suser:root user:nfsnobody
例子:統計磁碟使用量超過10%的分區。
按空格分隔,用第五列做判斷,第五列是Use%,17%,0%等,可以直接和10作比較。
其實原理是字元串比較,字母的ASCII碼大於數字,所以第一行也顯示出來了,完美實現要求。
# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/centos-root 38G 6.1G 31G 17% / devtmpfs 1.9G 0 1.9G 0% /dev tmpfs 1.9G 0 1.9G 0% /dev/shm tmpfs 1.9G 9.0M 1.9G 1% /run tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup /dev/sda1 1014M 179M 836M 18% /boot /dev/mapper/centos-home 19G 40M 19G 1% /home tmpfs 379M 0 379M 0% /run/user/0 # df -h | awk '{if($5>"10") print $0}' Filesystem Size Used Avail Use% Mounted on /dev/mapper/centos-root 38G 6.1G 31G 17% / /dev/sda1 1014M 179M 836M 18% /boot
switch(expression){case val1 or /pattern/: 語句; case val1 or /pattern/ 語句; ... default: 語句}
val是固定的值;pattern是正則表達式。
while(condition) {...}
統計/etc/fstab文件,U和/開頭的行是處理對象。把每列的字元串的長度算出來,顯示在列的後面,中間用冒號分隔。迴圈到最後一列時,列印換行。
# awk '/^[U\/]/{i=1;while(i<=NF) { printf "%s:%d ",$i,length($i); if(i==NF) {printf "\n"} i++} }' /etc/fstab /dev/mapper/centos-root:23 /:1 xfs:3 defaults:8 0:1 0:1 UUID=3d3b316a-529e-484a-9895-e785fdde5365:41 /boot:5 xfs:3 defaults:8 0:1 0:1 /dev/mapper/centos-home:23 /home:5 xfs:3 defaults:8 0:1 0:1 /dev/mapper/centos-swap:23 swap:4 swap:4 defaults:8 0:1 0:1
do{...} while(condition)
for(expr1;expr2;expr3){...}
統計/etc/fstab文件,U和/開頭的行是處理對象。把每列的字元串的長度算出來,顯示在列的後面,中間用冒號分隔。迴圈到最後一列時,列印換行。
# awk '/^[U\/]/{for(i=1;i<=NF;i++) { printf "%s:%d ",$i,length($i); if(i==NF) {printf "\n"} } }' /etc/fstab /dev/mapper/centos-root:23 /:1 xfs:3 defaults:8 0:1 0:1 UUID=3d3b316a-529e-484a-9895-e785fdde5365:41 /boot:5 xfs:3 defaults:8 0:1 0:1 /dev/mapper/centos-home:23 /home:5 xfs:3 defaults:8 0:1 0:1 /dev/mapper/centos-swap:23 swap:4 swap:4 defaults:8 0:1 0:1
遍曆數組的特殊用法:
for(var in array)
continue,bread[n](退出哪層迴圈)
next:提前退出當前行的處理,直接進入下一行。類似continue。
顯示uid是偶數的行。
# awk -F: '{ if($3%2)next;print $1,$3}' /etc/passwd root 0 daemon 2 lp 4 shutdown 6
delete arrary[index]:刪除數組的某個元素
delete array:刪除數組
exit:退出
2,input statements
3,output statements
數組
- 索引數組:索引是數字
- 關聯數組:索引是任意的字元串,字元串要用雙引號括起來。
當引用一個不存在的數組元素時,會自動創建之。數組索引是從1開始。
判斷某個索引是否存在,要使用特殊的語法:index in array
第一個wk["tur"]=12222a的12222a沒有用雙引號括起來,列印wk["tur"]的值變成了12222,自動把a去掉了。
# awk 'BEGIN{wk["mon"]="aaa";wk["tur"]=12222a; print wk["tur"]; print wk["mon"]}'
12222
aaa
[root@localhost ~]# awk 'BEGIN{wk["mon"]="aaa";wk["tur"]="1222a"; print wk["tur"]; print wk["mon"]}'
12222a
aaa
用for遍曆數組,i是數組的索引,而不是數組元素的值。
# awk 'BEGIN{wk["mon"]="aaa";wk["tur"]="12222a"} {for(i in wk)print i}' /etc/issue
tur
mon
tur
mon
tur
mon
[root@localhost ~]# awk 'BEGIN{wk["mon"]="aaa";wk["tur"]="12222a"} {for(i in wk)print wk[i]}' /etc/issue
12222a
aaa
12222a
aaa
12222a
aaa
統計每個狀態出現的次數之和。
# netstat -tan
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN
tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:6011 0.0.0.0:* LISTEN
tcp 0 64 192.168.56.107:22 192.168.56.1:60328 ESTABLISHED
tcp6 0 0 :::111 :::* LISTEN
tcp6 0 0 :::80 :::* LISTEN
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 ::1:631 :::* LISTEN
tcp6 0 0 ::1:6011 :::* LISTEN
# netstat -tan | awk '{if(NR==1 || NR==2)next; wk[$6]++} END{for(i in wk) printf "%s:%d times\n", i,wk[i]}'
LISTEN:10 times
ESTABLISHED:1 times
函數
1,內置函數
rand():隨機返回小於1的小數
split(要被分隔的串,存放分隔後的結果,分隔符):分隔字元串。
# netstat -tnl | awk '/^tcp\>/{split($4,ip,":"); print ip[1]}' 0.0.0.0 192.168.122.1 0.0.0.0 127.0.0.1 127.0.0.1
2,也支持自定義函數