1、awk
awk是一種編程語言,用於在Linux/unix下對文本和數據進行處理。數據可以來自標準輸入、一個或多個文件,或其他命令的輸出。awk支持函數、正則表達式、數組等先進功能。
awk處理文本和數據的方式是先逐行掃描文件,從第一到最後一行,尋找匹配的特定模式的行,並在這些找出的行上進行分段操作。如果沒有指定處理動作,則把匹配到的行顯示到標準輸出(屏幕),如果沒有指定模式,則所有被操作所指定的行都被處理,它可以在命令行中使用,更多是作爲腳本中一部分來使用。
2、awk中的變量
(1)awk的內置變量
FS(input field seperator):輸入時字段分隔符,默認爲空白字符;作用同-F參數
OFS(output field seperator):輸出時字段分隔符,默認爲空白字符;
RS(input record seperator):輸入時的換行符;
ORS(output record seperator):輸出時的換行符;
NF(number of field):字段數量
NR(number of record): 行數;多個文件和當一個文件對待
FNR:各文件分別計數,行數;
FILENAME:當前文件名;
ARGC:命令行參數的個數;
ARGV:數組,保存的是命令行所給定的各參數;
# FS的使用,作用同-F [root@node02 ~]# awk -v FS=':' '{print $1}' /etc/passwd|head -2 root bin [root@node02 ~]# awk -F: '{print $1}' /etc/passwd|head -2 root bin # 指定分隔符爲\t,換行符爲# [root@node02 ~]# head -2 /etc/passwd|awk -F: -v OFS="\t" -v ORS='#' '{print $1,$3}' root 0#bin 1 # NF爲輸出行字段的數量,$NF爲輸出最後一個字段 [root@node02 ~]# awk -F: '{print NF}' /etc/passwd|head -2 7 7 [root@node02 ~]# awk -F: '{print $NF}' /etc/passwd|head -2 /bin/bash /sbin/nologin # 輸出的每一行都會用該文件名來代替 [root@node02 ~]# awk '{print FILENAME}' /etc/fstab /etc/passwd /etc/fstab . . . . . . /etc/passwd # 每一行都會顯示參數的個數 [root@node02 ~]# awk '{print ARGC}' /etc/fstab /etc/passwd 3 3 . . . . . . # 只顯示一次參數的個數 [root@node02 ~]# awk 'BEGIN{print ARGC}' /etc/fstab /etc/passwd 3 # 顯示指定的參數,第0個參數爲awk自身 [root@node02 ~]# awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/passwd awk
(2)awk的內置變量
Awk中自定義變量時通過-v選項自定義變量,同時也可在在program中直接定定義。
[root@node02 ~]# awk -v test="hello awk" 'BEGIN{print test}' /etc/fstab hello awk [root@node02 ~]# awk 'BEGIN{test="awk";print test}' awk
3、awk中printf輸出命令的使用
Awk中printf也爲輸出,相對於print輸出,print不會自動換行,需要顯式給出換行控制符”\n”, FORMAT必須給出, FORMAT中需要分別爲後面的每個item指定一個格式化符號。
(1)使用printf輸出時的格式符
%c: 顯示字符的ASCII碼;
%d, %i: 顯示十進制整數;
%e, %E: 科學計數法數值顯示;
%f:顯示爲浮點數;
%g, %G:以科學計數法或浮點形式顯示數值;
%s:顯示字符串;
%u:無符號整數;
%%: 顯示%自身;
(2)使用printf輸出時的裝飾符
#[.#]:第一個數字控制顯示的寬度;第二個#表示小數點後的精度;
-: 左對齊
+:顯示數值的符號
# 默認輸出是不換行的 [root@node02 ~]# awk -F: '{printf "%s",$3}' /etc/passwd 01234567811121499192819997489998322965534997996995994993 # 使用\n換行輸出 [root@node02 ~]# awk -F: '{printf "username: %s \t uid:%d\n",$1,$3}' /etc/passwd|head -2 username: root uid:0 username: bin uid:1 # 輸出時左對齊並且用戶名字段的長度爲15個字符 [root@node02 ~]# awk -F: '{printf "username: %-15s \t uid:%d\n",$1,$3}' /etc/passwd| head -3 username: root uid:0 username: bin uid:1
4、awk中算術運算符
運算符 | 描述 |
= += -+ *= /= %= ^= **= | 賦值語句 |
|| && | 邏輯與、邏輯或 |
~ !~ | 匹配則正表達式和不匹配正則表達式 |
< <= > >= != == | 關係運算符 |
+ - * / & ** ++ -- | 算術運算符 |
$ | 字段引用 |
空格 | 字符串連接符 |
?: | 三目運算符 |
ln | 數組中是否存在某鍵值 |
# 打印非系統用戶 [root@node02 ~]# awk -F: '$3==0 || $3>=1000 {print $1,$3}' /etc/passwd root 0 nfsnobody 65534 # 三目運算判斷用戶的類型 [root@node02 ~]# awk -F: '{$3>=1000||$3==0?usertype="common user":usertype="system user";print$1,"-->"usertype}' /etc/passwd root -->common user bin -->system user
5、awk中的模式匹配
(1) empty:空模式,匹配每一行;
(2)/regular expression/:僅處理能夠被此處的模式匹配到的行;
(3)關係表達式;結果有“真”有“假”;結果爲“真”纔會被處理;真是結果爲非0值,非空字符串;
(4)行範圍的匹配,不支持直接給出數字的格式
(5)BEGIN/END模式, BEGIN{}僅在開始處理文件中的文本之前執行一次;END{}僅在文本處理完成之後執行一次;
# 輸出fstab文件中以UUID或/dev開頭的行 [root@node02 ~]# awk '/^UUID|^\/dev/{print $1}' /etc/fstab /dev/mapper/centos-root UUID=8dcf68e6-ba4c-4aaa-abd9-d008f1ecbe51 # 輸出uid大於1000的用戶 [root@node02 ~]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd nfsnobody 65534 # 輸出bash爲/bin/bash的用戶 [root@node02 ~]# awk -F: '$NF=="/bin/bash"{print $1,$3,$NF}' /etc/passwd root 0 /bin/bash # 行範圍的匹配 [root@node02 ~]# awk -F: '(NR>=2&&NR<=4){print $1}' /etc/passwd bin daemon adm # BEGIN/END模式輸出 [root@node02 ~]# awk -F: 'BEGIN{print "username\t\tuid\n------------------"}{printf "%s\t\t\t%d\n",$1,$3}END{print "=================================\nend"}' /etc/passwd|head -5 username uid ------------------ root 0 bin 1 daemon 2
6、awk中使用控制語句
awk中的條件語句是從C語言中借鑑過來的,可控制程序的流程.
(1)if-else語句
語句格式:if(condition) statement [else statement]
# 輸出bash爲“/bin/bash”的用戶 [root@node02 ~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd root # 判斷用戶類型 [root@node02 ~]# awk -F: '{if($3>=1000) {printf "Commonuser: %s\n",$1} else if($3==0){printf "admin-user: %s\n",$1} else {printf "Sysuser: %s\n",$1}}' /etc/passwd admin-user: root Sysuser: bin # 判斷一行的字數大於5個時輸出整行 [root@node02 ~]# awk '{if(NF>5) print $0}' /etc/fstab # Created by anaconda on Fri Jan 4 01:49:11 2019 # Accessible filesystems, by reference, are maintained under # 列出磁盤使用率大於等於10%的分區 [root@node02 ~]# df -h | awk -F[%] '/^\/dev/{print $1}' | awk '{if($NF>=10) print $1}' /dev/sda1
(2)while語句
While語句用於當條件成立時進入循環,當條件不成立時推出循環,常用於對一行內的多個字段逐一類似處理時或數組中的各元素逐一處理。
# 統計liunx所在行的每個字段的長度 [root@node02 ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg linux16 7 /vmlinuz-3.10.0-862.el7.x86_64 30 root=/dev/mapper/centos-root 28 # 統計liunx所在行的每個字段的長度並輸出長度大於7的字段及長度 [root@node02 ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)}; i++}}' /etc/grub2.cfg linux16 7 /vmlinuz-3.10.0-862.el7.x86_64 30 root=/dev/mapper/centos-root 28
(3)for語句
# 上面的案例使用for語句實現爲 [root@node02 ~]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) if(length($i)>=7){print $i,length($i)}}' /etc/grub2.cfg linux16 7 /vmlinuz-3.10.0-862.el7.x86_64 30 root=/dev/mapper/centos-root 28
(4)其他控制語句
除了上述常用的控制語句外,其他的控制語句還有do-while循環,switch語句,break和continue,next(前結束對本行的處理而直接進入下一行)。
7、awk中的數組
awk中的數組的下標可以是數字和字母,稱爲關聯數組;下標可使用任意字符串;字符串要使用雙引號;如果某數組元素事先不存在,在引用時,awk會自動創建此元素,並將其值初始化爲“空串”。
# 定義一個數組並遍歷輸出數組中的每個元素 [root@node02 ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}' Tuesday Monday # 統計每種TCP狀態的數量 [root@node02 ~]# netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state) { print i,state[i]}}' LISTEN 19 ESTABLISHED 24 TIME_WAIT 3 # 統計fstab中每種類型的文件系統出現的次數 [root@node02 ~]# awk '/^UUID|^\/dev/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab swap 1 xfs 2 # 統計fstab中每個字段出現的次數 [root@node02 ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab swap 2 fstab(5), 1
8、awk中的函數
awk中常用的內置函數有:
rand():返回0和1之間一個隨機數;
length([s]):返回指定字符串的長度;
sub(r,s,[t]):以r表示的模式來查找t所表示的字符中的匹配的內容,並將其第一次出現替換爲s所表示的內容;
gsub(r,s,[t]):以r表示的模式來查找t所表示的字符中的匹配的內容,並將其所有出現均替換爲s所表示的內容;
split(s,a[,r]):以r爲分隔符切割字符s,並將切割後的結果保存至a所表示的數組中;
# 統計機同外部每個ip建立tcp連接的數量 [root@node02 ~]# netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}' 192.168.17.195 1 192.168.17.196 3 # 將匹配到的第一個root替換爲admin [root@node02 ~]# awk -F: '{ sub(/root/, "admin"); print }' /etc/passwd admin:x:0:0:root:/root:/bin/bash