案例1:插入幾個新字段
在”a b c d”的b後面插入3個字段e f g
思路:在b後面插入e f g相當於在c前面插入e f g
Note:修改字段(會反饋給$0,相當於修改了$0)或者修改$0後會重建$0(根據OFS重建$0),OFS的默認值是一個空格。
案列2:格式化空白
移除每行的前綴、後綴、空白,並將各部分左對齊
原始文檔格式
直接給字段賦原值就可以格式化文本,因爲更改字段會以OFS重建$0
上面的方法是以單個空格隔開每個字段,但是我們想用製表符隔開每個字段的話,因該如下操作
案列3:篩選IPv4地址
從ifconfig命令的結果中篩選出除了lo網卡外的所有IPv4地址
方法1:
#ifconfig | awk '/inet / && !($2 ~ /^127/){print $2}'
方法2:
按段落讀取,默認情況下awk是以行讀取,所以需要修改輸入分割控制符(RS)
RS="":按段落讀取
RS="\0":一次性讀取所有數據,但有些特殊文件中包含了空字符\0
RS="^$":真正的一次性讀取所有數據,因爲非空文件不可能匹配成功
RS="\n+":按行讀取,但忽略所有空行
#ifconfig | awk 'BEGIN{RS=""}{print}'
只輸出第一段落
#ifconfig |awk 'BEGIN{RS=""}NR==1{print}'
取得ip地址,需要知道其在第幾個字段,字段默認是以空格劃分的,所以數一下ip在第幾個字段,注意換行符也是空格,所以ip在地6個字段
#ifconfig |awk 'BEGIN{RS=""}NR==1{print $6}'
但是以上取法不是很好,會受到網卡的排列順序影響,進一步改進,將lo開頭的網卡排除在外即可
#ifconfig |awk 'BEGIN{RS=""}!/^lo:/{print $6}'
方法3:
取出段後再按行劃分字段(以換行符劃分)
#ifconfig |awk 'BEGIN{RS="";FS="\n"}!/^lo:/{$0=$2;FS=" ";$0=$0;print $2}'
案例4:讀取.repo配置文件中的某段
本例選取yum源的配置文件CentOS-Base.repo作爲實驗素材,原文如下:
# CentOS-Base.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client. You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# If the mirrorlist= does not work for you, as a fall back you can try the
# remarked out baseurl= line instead.
#
#
[base]
name=CentOS-$releasever - Base - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/os/$basearch/
http://mirrors.aliyuncs.com/centos/$releasever/os/$basearch/
http://mirrors.cloud.aliyuncs.com/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
#released updates
[updates]
name=CentOS-$releasever - Updates - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/updates/$basearch/
http://mirrors.aliyuncs.com/centos/$releasever/updates/$basearch/
http://mirrors.cloud.aliyuncs.com/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/extras/$basearch/
http://mirrors.aliyuncs.com/centos/$releasever/extras/$basearch/
http://mirrors.cloud.aliyuncs.com/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/centosplus/$basearch/
http://mirrors.aliyuncs.com/centos/$releasever/centosplus/$basearch/
http://mirrors.cloud.aliyuncs.com/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
#contrib - packages by Centos Users
[contrib]
name=CentOS-$releasever - Contrib - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/contrib/$basearch/
http://mirrors.aliyuncs.com/centos/$releasever/contrib/$basearch/
http://mirrors.cloud.aliyuncs.com/centos/$releasever/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
假設現在要取出[base]段的文本,首先創建一個名爲test1.awk
的文件,然後編寫腳本
[root@localhost yum.repos.d]# touch test1.awk
[root@localhost yum.repos.d]# ls
CentOS-Base.repo CentOS-SCLo-scl-rh.repo test1.awk
正則中需要轉義的特殊字符如下:
$ 匹配輸入字符串的結尾位置。如果設置了 RegExp 對象的 Multiline 屬性,則 $ 也匹配 ‘\n' 或 ‘\r'。要匹配 $ 字符本身,請使用 \$
( ) 標記一個子表達式的開始和結束位置。子表達式可以獲取供以後使用。要匹配這些字符,請使用 \( 和 \)
* 匹配前面的子表達式零次或多次。要匹配 * 字符,請使用 \*
+ 匹配前面的子表達式一次或多次。要匹配 + 字符,請使用 \+
. 匹配除換行符 \n之外的任何單字符。要匹配 .,請使用 \
[ ] 標記一箇中括號表達式的開始。要匹配 [,請使用 \[
? 匹配前面的子表達式零次或一次,或指明一個非貪婪限定符。要匹配 ? 字符,請使用 \?
\ 將下一個字符標記爲或特殊字符、或原義字符、或向後引用、或八進制轉義符。例如, ‘n' 匹配字符 ‘n'。'\n' 匹配換行符。序列 ‘\\' 匹配 “\”,而 ‘\(' 則匹配 “(”
^ 匹配輸入字符串的開始位置,除非在方括號表達式中使用,此時它表示不接受該字符集合。要匹配 ^ 字符本身,請使用 \^。
{ } 標記限定符表達式的開始。要匹配 {,請使用 \{
| 指明兩項之間的一個選擇。要匹配 |,請使用 \|
#/\[base\]/ 字符不確定的情況下使用這種方法
#字符確定的情況下使用index
#對於確定字符串可以使用index進行搜索,在$0中進行搜索,當其中的字串存在[base]時候,返回其索引位,索引位是大於零的,從1開始
index($0,"[base]"){
print
while( (getline var) >0 ){
if (var ~ /\[.*\]/){
exit
}
print var
}
}
#getline()的說明
#當getline()的返回值大於零時,表示已經取到數據
#當getline()的返回值等於零時,表示遇到結尾EOF,也就是沒有讀取到符合條件的字符
#當getline()的返回值小於零時,表示讀取報錯,沒有權限等
#var ~ /\[.*\]/ 如果匹配到其他的就退出
案列5:根據某個字段去重
去掉 uid=xxx 重複的行
可以根據第一次出現去重,也可以根據最後一次出現去重
2019-01-13_12:00_index?uid=123
2019-01-13_13:00_index?uid=123
2019-01-13_14:00_index?uid=333
2019-01-13_15:00_index?uid=9710
2019-01-14_12:00_index?uid=123
2019-01-14_13:00_index?uid=123
2019-01-15_14:00_index?uid=333
2019-01-16_15:00_index?uid=9710
先將每一行以問號爲界限劃分爲兩個字段,然後將$2放入數組arr,統計$2出現的次數,如果只出現一次則輸出,如出現多次只輸出第一次出現的值
#awk -F "?" '{arr[$2]=arr[$2]+1;if(arr[$2]==1){print}}' test2.txt
也可以改爲自增運算:
#awk -F "?" '{arr[$2]++;if(arr[$2]==1){print}}' test2.txt
或者
#awk -F "?" '{++arr[$2];if(arr[$2]==1){print}}' test2.txt
更進一步改進:
#awk -F "?" '!arr[$2]++{print}' test2.txt
#當第一次讀取到時arr[0]返回0,取反後返回爲真,則輸出;第二次讀取到時,返回1,取反後爲假,則不輸出
#而且print也可以省略,因爲awk默認會輸出
#awk -F "?" '!arr[$2]++' test2.txt
案列6:用awk數組做次數統計
(1)次數統計
統計的素材如下:
portmapper
portmapper
portmapper
portmapper
portmapper
portmapper
status
status
mountd
mountd
mountd
mountd
mountd
mountd
nfs
nfs
nfs_acl
nfs
nfs
nfs_acl
nlockmgr
nlockmgr
nlockmgr
nlockmgr
nlockmgr
#awk '{arr[$0]++}END{OFS="\t";for(i in arr){print arr[i],i}}' test3.txt
(2)統計TCP連接狀態數量
#netstat -tnap
狀態state字段是$6,將其放入數組中進行統計
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 192.168.33.99:25 0.0.0.0:* LISTEN 2388/master
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 2388/master
tcp 0 0 127.0.0.1:6010 0.0.0.0:* LISTEN 3313/sshd: root@pts
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 1114/redis-server 1
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 1726/rpcbind
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1595/sshd
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 2957/cupsd
tcp 0 0 0.0.0.0:52856 0.0.0.0:* LISTEN 1816/rpc.statd
tcp 0 0 192.168.33.99:22 192.168.33.102:52093 ESTABLISHED 3313/sshd: root@pts
tcp6 0 0 ::1:25 :::* LISTEN 2388/master
tcp6 0 0 ::1:6010 :::* LISTEN 3313/sshd: root@pts
tcp6 0 0 :::42719 :::* LISTEN 1816/rpc.statd
tcp6 0 0 :::111 :::* LISTEN 1726/rpcbind
tcp6 0 0 :::22 :::* LISTEN 1595/sshd
tcp6 0 0 ::1:631 :::* LISTEN 2957/cupsd
#netstat -nat|awk '/^tcp /{arr[$6]++}END{for(state in arr){print arr[state]":"state}}'
#netstat -nat | grep 'tcp' | awk '{print $6}'|sort | uniq -c
案列6:統計日誌中特定條件的字段出現的次數
(1)統計日誌中非200狀態碼的IP出現的次數
#awk '$8!=200{arr[$1]++}END{for(i in arr){print arr[i],i}}' access.log
進一步統計出現次數排名前十的IP:
#awk '$8!=200{arr[$1]++}END{for(i in arr){print arr[i],i}}' access.log | sort -k1nr | head -n 10
另外一種實現統計前十的 方法:
#awk '$8!=200{arr[$1]++}END{PROCINFO["sorted_in"]="@val_num_desc";for(i in arr){if(cnt++==10){exit}print arr[i],i}}' access.log