這些案例是我收集起來的,大多都是我本身遇到過的,有些比較經典,有些比較具備表明性。mysql
在"a b c d"的b後面插入3個字段e f g
。sql
echo a b c d|awk '{$3="e f g "$3}1'
移除每行的前綴、後綴空白,並將各部分左對齊。centos
aaaa bbb ccc bbb aaa ccc ddd fff eee gg hh ii jj
awk 'BEGIN{OFS="\t"}{$1=$1;print}' a.txt
執行結果:api
aaaa bbb ccc bbb aaa ccc ddd fff eee gg hh ii jj
從ifconfig命令的結果中篩選出除了lo網卡外的全部IPv4地址。bash
## 1.法一: ifconfig | awk '/inet / && !($2 ~ /^127/){print $2}' # 按段落讀取 ## 2.法二: ifconfig | awk 'BEGIN{RS=""}!/lo/{print $6}' ## 3.法三: ifconfig |\ awk ' BEGIN{RS="";FS="\n"} !/lo/{$0=$2;FS=" ";$0=$0;print $2} '
ini文件內容以下:app
[base] name=os_repo baseurl=https://xxx/centos/$releasever/os/$basearch gpgcheck=0 enable=1 [mysql] name=mysql_repo baseurl=https://xxx/mysql-repo/yum/mysql-5.7-community/el/$releasever/$basearch gpgcheck=0 enable=1 [epel] name=epel_repo baseurl=https://xxx/epel/$releasever/$basearch gpgcheck=0 enable=1 [percona] name=percona_repo baseurl = https://xxx/percona/release/$releasever/RPMS/$basearch enabled = 1 gpgcheck = 0
awk篩選代碼以下:ssh
awk ' index($0,"[mysql]"){ print; while( (getline)>0 ){ if(/\[.*\]/){ exit } print } }' a.txt
去掉uid=xxx
重複的行。tcp
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
awk -F"?" '!arr[$2]++{print}' a.txt
結果:ide
2019-01-13_12:00_index?uid=123 2019-01-13_14:00_index?uid=333 2019-01-13_15:00_index?uid=9710
假設有以下文件內容,統計每一行出現的次數:函數
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代碼以下:
awk '{a[$1]++}END{for(i in arr){print a[i],i}}' a.txt
以下tcp鏈接狀態信息:
$ netstat -tnap Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1139/sshd tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 2285/master tcp 0 96 192.168.2.17:22 192.168.2.1:2468 ESTABLISHED 87463/sshd: root@pt tcp 0 0 192.168.2017:22 192.168.201:5821 ESTABLISHED 89359/sshd: root@no tcp6 0 0 :::3306 :::* LISTEN 2289/mysqld tcp6 0 0 :::22 :::* LISTEN 1139/sshd tcp6 0 0 ::1:25 :::* LISTEN 2285/master
統計但願獲得的結果:
5: LISTEN 2: ESTABLISHED
netstat -tnap |\ awk ' /^tcp/{arr[$6]++} END{ for(state in arr){ print arr[state] ": " state } } '
一行式:
netstat -tna | awk '/^tcp/{arr[$6]++}END{for(state in arr){print arr[state] ": " state}}' netstat -tna | /usr/bin/grep 'tcp' | awk '{print $6}' | sort | uniq -c
日誌示例數據:
111.202.100.141 - - [2019-11-07T03:11:02+08:00] "GET /robots.txt HTTP/1.1" 301 169
統計非200狀態碼的IP,並取次數最多的前10個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
假設有以下文件內容,總共4個字段,第一個字段是URL,第二個字段是訪問IP,第三個字段是訪問時間,第四個字段是訪問人。
a.com.cn|202.109.134.23|2015-11-20 20:34:43|guest b.com.cn|202.109.134.23|2015-11-20 20:34:48|guest c.com.cn|202.109.134.24|2015-11-20 20:34:48|guest a.com.cn|202.109.134.23|2015-11-20 20:34:43|guest a.com.cn|202.109.134.24|2015-11-20 20:34:43|guest b.com.cn|202.109.134.25|2015-11-20 20:34:48|guest
需求:統計每一個URL的獨立訪問IP有多少個(去重),而且要爲每一個URL保存一個對應的文件,獲得的結果相似:
a.com.cn 2 b.com.cn 2 c.com.cn 1
而且有三個對應的文件:
a.com.cn.txt b.com.cn.txt c.com.cn.txt
代碼:
BEGIN{ FS="|" } !arr[$1,$2]++{ arr1[$1]++ } END{ for(i in arr1){ print i,arr1[i] >(i".txt") } }
有以下文件內容,其中幾個字段是缺失數據的:
ID name gender age email phone 1 Bob male 28 abc@qq.com 18023394012 2 Alice female 24 def@gmail.com 18084925203 3 Tony male 21 17048792503 4 Kevin male 21 bbb@189.com 17023929033 5 Alex male 18 ccc@xyz.com 18185904230 6 Andy female ddd@139.com 18923902352 7 Jerry female 25 exdsa@189.com 18785234906 8 Peter male 20 bax@qq.com 17729348758 9 Steven 23 bc@sohu.com 15947893212 10 Bruce female 27 bcbd@139.com 13942943905
當字段缺失時,直接使用FS劃分字段來處理會很是棘手。gawk爲了解決這種特殊需求,提供了FIELDWIDTHS變量。
FIELDWIDTH能夠按照字符數量劃分字段。
awk '{print $4}' FIELDWIDTHS="2 2:6 2:6 2:3 2:13 2:11" a.txt
此處FIELDWIDTHS變量的值表示的含義:
這樣按給定字符數量取字段數據後,即便字段缺失,也不會影響其它字段的數據。
下面是CSV文件中的一行,該CSV文件以逗號分隔各個字段。
Robbins,Arnold,"1234 A Pretty Street, NE",MyTown,MyState,12345-6789,USA
需求:取得第三個字段"1234 A Pretty Street, NE"。
當字段中包含了字段分隔符時,直接使用FS劃分字段來處理會很是棘手。gawk爲了解決這種特殊需求,提供了FPAT變量。
FPAT能夠收集正則匹配的結果,並將它們保存在各個字段中(就像grep匹配成功的部分會加顏色顯示,而使用FPAT劃分字段,則是將匹配成功的部分保存在字段$1 $2 $3...
中)。
echo 'Robbins,Arnold,"1234 A Pretty Street, NE",MyTown,MyState,12345-6789,USA' |\ awk 'BEGIN{FPAT="[^,]+|\".*\""}{print $1,$3}'
給定數據:
16 001agdcdafasd 16 002agdcxxxxxx 23 001adfadfahoh 23 001fsdadggggg
但願獲得:
16 001 16 002 23 001 23 002
awk的代碼:
awk '{print $1,substr($2,1,3)}' awk 'BEGIN{FIELDWIDTH="2 2:3"}{print $1,$2}' a.txt
給定數據:
name age alice 21 ryan 30
但願轉換後獲得:
name alice ryan age 21 30
awk代碼:
awk ' { for(i=1;i<=NF;i++){ if(!(i in arr)){ arr[i]=$i } else { arr[i]=arr[i]" "$i } } } END{ for(i=1;i<=NF;i++){ print arr[i] } } ' a.txt
文件內容:
74683 1001 74683 1002 74683 1011 74684 1000 74684 1001 74684 1002 74685 1001 74685 1011 74686 1000 .... 100085 1000 100085 1001
文件就兩列,但願處理成:
74683 1001 1002 1011 74684 1000 1001 1002 ...
即,只要第一列數字相同,就把它們的第二列放一行上,中間空格分開。
代碼:
{ if($1 in arr){ arr[$1] = arr[$1]" "$2 } else { arr[$1] = $2 } } END{ for(i in arr){ printf "%s %s\n",i,arr[i] } }
grep/sed/awk用正則去篩選日誌時,若是要精確到小時、分鐘、秒,則很是難以實現。
可是awk提供了mktime()函數,它能夠將時間轉換成epoch時間值。
# 2019-11-10 03:42:40轉換成epoch $ awk 'BEGIN{print mktime("2019 11 10 03 42 40")}' 1573328560
藉此,能夠取得日誌中的時間字符串部分,再將它們的年、月、日、時、分、秒都取出來,而後放入mktime()構建成對應的epoch值。由於epoch值是數值,因此能夠比較大小,從而決定時間的大小。
下面strptime1()實現的是將2019-11-10T03:42:40+08:00
格式的字符串轉換成epoch值,而後和which_time比較大小便可篩選出精確到秒的日誌。
BEGIN{ # 要篩選什麼時間的日誌,將其時間構建成epoch值 which_time = mktime("2019 11 10 03 42 40") } { # 取出日誌中的日期時間字符串部分 match($0,"^.*\\[(.*)\\].*",arr) # 將日期時間字符串轉換爲epoch值 tmp_time = strptime1(arr[1]) # 經過比較epoch值來比較時間大小 if(tmp_time > which_time){print} } # 構建的時間字符串格式爲:"2019-11-10T03:42:40+08:00" function strptime1(str ,arr,Y,M,D,H,m,S) { patsplit(str,arr,"[0-9]{1,4}") Y=arr[1] M=arr[2] D=arr[3] H=arr[4] m=arr[5] S=arr[6] return mktime(sprintf("%s %s %s %s %s %s",Y,M,D,H,m,S)) }
下面strptime2()實現的是將10/Nov/2019:23:53:44+08:00
格式的字符串轉換成epoch值,而後和which_time比較大小便可篩選出精確到秒的日誌。
BEGIN{ which_time = mktime("2019 11 10 03 42 40") } { match($0,"^.*\\[(.*)\\].*",arr) tmp_time = strptime2(arr[1]) if(tmp_time > which_time){ print } } # 構建的時間字符串格式爲:"10/Nov/2019:23:53:44+08:00" function strptime2(str ,dt_str,arr,Y,M,D,H,m,S) { dt_str = gensub("[/:+]"," ","g",str) # dt_sr = "10 Nov 2019 23 53 44 08 00" split(dt_str,arr," ") Y=arr[3] M=mon_map(arr[2]) D=arr[1] H=arr[4] m=arr[5] S=arr[6] return mktime(sprintf("%s %s %s %s %s %s",Y,M,D,H,m,S)) } function mon_map(str ,mons){ mons["Jan"]=1 mons["Feb"]=2 mons["Mar"]=3 mons["Apr"]=4 mons["May"]=5 mons["Jun"]=6 mons["Jul"]=7 mons["Aug"]=8 mons["Sep"]=9 mons["Oct"]=10 mons["Nov"]=11 mons["Dec"]=12 return mons[str] }
/**/
中間的註釋示例數據:
/*AAAAAAAAAA*/ 1111 222 /*aaaaaaaaa*/ 32323 12341234 12134 /*bbbbbbbbbb*/ 132412 14534122 /* cccccccccc */ xxxxxx /*ddddddddddd cccccccccc eeeeeee */ yyyyyyyy 5642341
awk代碼:
# 註釋內的行 /\/\*/{ # 同行有"*/" if(/\*\//){ print gensub("(.*)/\\*.*\\*/(.*)","\\1\\2","g",$0) } else { # 同行沒有"*/" # 1.去掉/*行後的內容 print gensub("(.*)/\\*.*","\\1","g",$0) # 2.繼續讀取,直到出現*/,並去掉中間的全部數據 while( ( getline ) > 0 ){ # 出現了*/行 if(/\*\//){ print gensub(".*\\*/(.*)","\\1","g",$0) } } } } # 非註釋內容 !/\/\*/{print}
從以下類型的文件中,找出false段的前一段爲i-order的段,同時輸出這兩段。
2019-09-12 07:16:27 [-][ 'data' => [ 'http://192.168.100.20:2800/api/payment/i-order', ], ] 2019-09-12 07:16:27 [-][ 'data' => [ false, ], ] 2019-09-21 07:16:27 [-][ 'data' => [ 'http://192.168.100.20:2800/api/payment/i-order', ], ] 2019-09-21 07:16:27 [-][ 'data' => [ 'http://192.168.100.20:2800/api/payment/i-user', ], ] 2019-09-17 18:34:37 [-][ 'data' => [ false, ], ]
awk代碼:
BEGIN{ RS="]\n" ORS=RS } { if(/false/ && prev ~ /i-order/){ print tmp print } tmp=$0 }
有兩個文件file1和file2,這兩個文件格式都是同樣的。
需求:先把文件2的第五列刪除,而後用文件2的第一列減去文件一的第一列,把所得結果對應的貼到原來第五列的位置,請問這個腳本該怎麼編寫?
file1: 50.481 64.634 40.573 1.00 0.00 51.877 65.004 40.226 1.00 0.00 52.258 64.681 39.113 1.00 0.00 52.418 65.846 40.925 1.00 0.00 49.515 65.641 40.554 1.00 0.00 49.802 66.666 40.358 1.00 0.00 48.176 65.344 40.766 1.00 0.00 47.428 66.127 40.732 1.00 0.00 51.087 62.165 40.940 1.00 0.00 52.289 62.334 40.897 1.00 0.00 file2: 48.420 62.001 41.252 1.00 0.00 45.555 61.598 41.361 1.00 0.00 45.815 61.402 40.325 1.00 0.00 44.873 60.641 42.111 1.00 0.00 44.617 59.688 41.648 1.00 0.00 44.500 60.911 43.433 1.00 0.00 43.691 59.887 44.228 1.00 0.00 43.980 58.629 43.859 1.00 0.00 42.372 60.069 44.032 1.00 0.00 43.914 59.977 45.551 1.00 0.00
# 方法一: awk '{ f1 = $1 if( (getline <"file2") >= 0 ){ $5 = $1 - f1 print $0 } }' file1 # 方法二: awk ' NR==FNR{arr[FNR]=$1} NR!=FNR{$5=$1-arr[FNR];print} ' file1 file2