awk實際使用案例

知識點:

1)數組

數組是用來存儲一系列值的變量,可通過索引來訪問數組的值。

Awk中數組稱為關聯數組,因為它的下標(索引)可以是數字也可以是字符串。

下標通常稱為鍵,數組元素的鍵和值存儲在Awk程序內部的一個表中,該表采用散列算法,因此數組元素是隨機排序。

數組格式:array[index]=value

1、Nginx日志分析

    日志格式:’$remote_addr – $remote_user [$time_local] “$request” $status $body_bytes_sent “$http_referer” “$http_user_agent” “$http_x_forwarded_for”‘

    日志記錄:27.189.231.39 – – [09/Apr/2016:17:21:23 +0800] “GET /Public/index/images/icon_pre.png HTTP/1.1” 200 44668 “http://www.test.com/Public/index/css/global.css” “Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36” “-“

    1)統計日志中訪問最多的10個IP

        思路:對第一列進行去重,并輸出出現的次數

        方法1:$ awk ‘{a[$1]++}END{for(i in a)print a[i],i|”sort -k1 -nr|head -n10″}’ access.log

        方法2:$ awk ‘{print $1}’ access.log |sort |uniq -c |sort -k1 -nr |head -n10

        說明:a[$1]++ 創建數組a,以第一列作為下標,使用運算符++作為數組元素,元素初始值為0。處理一個IP時,下標是IP,元素加1,處理第二個IP時,下標是IP,元素加1,如果這個IP已經存在,則元素再加1,也就是這個IP出現了兩次,元素結果是2,以此類推。因此可以實現去重,統計出現次數。

    2)統計日志中訪問大于100次的IP

        方法1:$ awk ‘{a[$1]++}END{for(i in a){if(a[i]>100)print i,a[i]}}’ access.log

        方法2:$ awk ‘{a[$1]++;if(a[$1]>100){b[$1]++}}END{for(i in b){print i,a[i]}}’ access.log

        說明:方法1是將結果保存a數組后,輸出時判斷符合要求的IP。方法2是將結果保存a數組時,并判斷符合要求的IP放到b數組,最后打印b數組的IP。

    3)統計2016年4月9日一天內訪問最多的10個IP

        思路:先過濾出這個時間段的日志,然后去重,統計出現次數

        方法1:$ awk ‘$4>=”[9/Apr/2016:00:00:01″ && $4<=”[9/Apr/2016:23:59:59″ {a[$1]++}END{for(i in a)print a[i],i|”sort -k1 -nr|head -n10″}’ access.log

        方法2:$ sed -n ‘/\[9\/Apr\/2016:00:00:01/,/\[9\/Apr\/2016:23:59:59/p’ access.log |sort |uniq -c |sort -k1 -nr |head -n10  #前提開始時間與結束時間日志中必須存在

    4)統計當前時間前一分鐘的訪問數

        思路:先獲取當前時間前一分鐘對應日志格式的時間,再匹配統計

        $ date=$(date -d ‘-1 minute’ +%d/%b/%Y:%H:%M);awk -vdate=$date ‘$0~date{c++}END{print c}’ access.log

        $ date=$(date -d ‘-1 minute’ +%d/%b/%Y:%H:%M);awk -vdate=$date ‘$4>=”[“date”:00″ && $4<=”[“date”:59″{c++}END{print c}’ access.log

        $ grep -c $(date -d ‘-1 minute’ +%d/%b/%Y:%H:%M) access.log

        說明:date +%d/%b/%Y:%H:%M –> 09/Apr/2016:01:55

    5)統計訪問最多的前10個頁面($request)

        $ awk ‘{a[$7]++}END{for(i in a)print a[i],i|”sort -k1 -nr|head -n10″}’ access.log

    6)統計每個URL訪問內容的總大小($body_bytes_sent)

        $ awk ‘{a[$7]++;size[$7]+=$10}END{for(i in a)print a[i],size[i],i}’ access.log

    7)統計每個IP訪問狀態碼數量($status)

        $ awk ‘{a[$1″ “$9]++}END{for(i in a)print i,a[i]}’ access.log

    8)統計訪問狀態碼為404的IP及出現次數

        $ awk ‘{if($9~/404/)a[$1″ “$9]++}END{for(i in a)print i,a[i]}’ access.log

2、兩個文件對比

    文件內容如下:

    $ cat a

    1

    2

    3

    4

    5

    6

    $ cat b

    3

    4

    5

    6

    7

    8

    1)找出相同記錄

        方法1:$ awk ‘FNR==NR{a[$0];next}($0 in a)’ a b

        3

        4

        5

        6

        解釋前,先看下FNR和NR區別:

        $ awk ‘{print NR,$0}’ a b

        1 1

        2 2

        3 3

        4 4

        5 5

        6 6

        7 3

        8 4

        9 5

        10 6

        11 7

        12 8

        $ awk ‘{print FNR,$0}’ a b

        1 1

        2 2

        3 3

        4 4

        5 5

        6 6

        1 3

        2 4

        3 5

        4 6

        5 7

        6 8

        可以看出NR是處理一行記錄,編號就會加1,同時也可以看到awk將兩個文件當成一個合并后的文件處理。

        而FNR則是處理一行記錄,編號也會加1,但是,處理到第二個文件時,編號重新計數。

        說明:FNR和NR是內置變量。FNR==NR常用于對兩個文件處理,這個例子可以理解為awk將兩個文件當成一個文件處理。

        處理a文件時,FNR是等于NR的,條件為真,執行a[$0],next表達式,意思是將每條記錄存放到a數組作為下標(無元素),next是跳出,類似于continue,不執行后面表達式。

        執行過程以此類推,直到處理b件時,FNR不等于NR(FNR重新計數是1,NR繼續加1是7),條件為假,不執行后面a[$0],next表達式,直接執行($0 in a)表達式,這句意思是處理b文件第一條繼續判斷是否在a數組中,如果在則打印這條記錄,以此類推。

        這樣可能更好理解些:

        $ awk ‘FNR==NR{a[$0]}NR>FNR{if($0 in a)print $0}’ a b

        方法2:

        $ awk ‘FNR==NR{a[$0]=1;next}(a[$0])’ a b   #小括號可以不加

        $ awk ‘FNR==NR{a[$0]=1;next}(a[$0]==1)’ a b

        $ awk ‘FNR==NR{a[$0]=1;next}{if(a[$0]==1)print}’ a b

        $ awk ‘FNR==NR{a[$0]=1}FNR!=NR&&a[$0]==1’ a b

        說明:先要知道后面的a[$0]不是一個數組,而是通過下標(b文件每條記錄)來訪問a數組元素。如果a[b的一行記錄]獲取的a數組元素是1,則為真,也就是等于1,打印這條記錄,否則獲取不到元素,則為假。

        方法3:

        $ awk ‘ARGIND==1{a[$0]=1}ARGIND==2&&a[$0]==1’ a b

        $ awk ‘FILENAME==”a”{a[$0]=1}FILENAME==”b”&&a[$0]==1’ a b

        說明:ARGIND內置變量,處理文件標識符,第一個文件為1,第二個文件為2。FILENAME也是內置變量,表示輸入文件的名字

        方法4:$ sort a b |uniq -d

        方法5:$ grep -f a b

    2)找不同記錄(同上,取反)

        $ awk ‘FNR==NR{a[$0];next}!($0 in a)’ a b

        $ awk ‘FNR==NR{a[$0]=1;next}!a[$0]’ a b

        $ awk ‘ARGIND==1{a[$0]=1}ARGIND==2&&a[$0]!=1’ a b

        $ awk ‘FILENAME==”a”{a[$0]=1}FILENAME==”b”&&a[$0]!=1’ a b

        7

        8

        方法2:$ sort a b |uniq -d

        方法3:$ grep -vf a b

3、合并兩個文件

    1)將d文件性別合并到c文件

        $ cat c

        zhangsan 100

        lisi 200

        wangwu 300

        $ cat d

        zhangsan man

        lisi woman

        方法1:$ awk  ‘FNR==NR{a[$1]=$0;next}{print a[$1],$2}’ c d

        zhangsan 100  man

        lisi 200 woman

        wangwu 300 man

        方法2:$ awk  ‘FNR==NR{a[$1]=$0}NR>FNR{print a[$1],$2}’ c d

        說明:NR==FNR匹配第一個文件,NR>FNR匹配第二個文件,將$1為數組下標

        方法3:$ awk ‘ARGIND==1{a[$1]=$0}ARGIND==2{print a[$1],$2}’ c d

    2)將a.txt文件中服務名稱合并到一個IP中

    $ cat a.txt

    192.168.2.100 : httpd

    192.168.2.100 : tomcat

    192.168.2.101 : httpd

    192.168.2.101 : postfix

    192.168.2.102 : mysqld

    192.168.2.102 : httpd

    $ awk -F: -vOFS=”:” ‘{a[$1]=a[$1] $2}END{for(i in a)print i,a[i]}’ a.txt

    $ awk -F: -vOFS=”:” ‘{a[$1]=$2 a[$1]}END{for(i in a)print i,a[i]}’ a.txt

    192.168.2.100 : httpd  tomcat

    192.168.2.101 : httpd  postfix

    192.168.2.102 : mysqld  httpd

    說明:a[$1]=$2 第一列為下標,第二個列是元素,后面跟的a[$1]是通過第一列取a數組元素(服務名),結果是$1=$2 $2,并作為a數組元素。

    3)將第一行附加給下面每行開頭

    $ cat a.txt

    xiaoli

    a 100

    b 110

    c 120

    $ awk ‘NF==1{a=$0;next}{print a,$0}’ a.txt

    $ awk ‘NF==1{a=$0}NF!=1{print a,$0}’ a.txt

    xiaoli  a 100

    xiaoli  b 110

    xiaoli  c 120

4、倒敘列打印文本

    $ cat a.txt

    xiaoli   a 100

    xiaoli   b 110

    xiaoli   c 120

    $ awk ‘{for(i=NF;i>=1;i–){printf “%s “,$i}print s}’ a.txt

    100 a xiaoli

    110 b xiaoli

    120 c xiaoli

    $ awk ‘{for(i=NF;i>=1;i–)if(i==1)printf $i”\n”;else printf $i” “}’ a.txt

    說明:利用NF降序輸出,把最后一個域作為第一個輸出,然后自減,print s或print “”打印一個換行符

5、從第二列打印到最后

    方法1:$ awk ‘{for(i=2;i<=NF;i++)if(i==NF)printf $i”\n”;else printf $i” “}’ a.txt

    方法2:$ awk ‘{$1=””}{print $0}’ a.txt

    a 100

    b 110

    c 120

6、將c文件中第一列放到到d文件中的第三列

    $ cat c

    a

    b

    c

    $ cat d

    1 one

    2 two

    3 three

    方法1:$ awk ‘FNR==NR{a[NR]=$0;next}{$3=a[FNR]}1’ c d

    說明:以NR編號為下標,元素是每行,當處理d文件時第三列等于獲取a數據FNR(重新計數1-3)編號作為下標。

    方法2:$ awk ‘{getline f<“c”;print $0,f}’ d

    1 one a

    2 two b

    3 three c

    1)替換第二列

    $ awk ‘{getline f<“c”;gsub($2,f,$2)}1’ d

    1 a

    2 b

    3 c

    2)替換第二列的two

    $ awk ‘{getline f<“c”;gsub(“two”,f,$2)}1’ d

    1 one

    2 b

    3 three

7、數字求和

    方法1:$ seq 1 100 |awk ‘{sum+=$0}END{print sum}’

    方法2:$ awk ‘BEGIN{sum=0;i=1;while(i<=100){sum+=i;i++}print sum}’

    方法3:$ awk ‘BEGIN{for(i=1;i<=100;i++)sum+=i}END{print sum}’ /dev/null

    方法4:$ seq -s + 1 100 |bc

8、每隔三行添加一個換行符或內容

    方法1:$ awk ‘$0;NR%3==0{printf “\n”}’ a

    方法2:$ awk ‘{print NR%3?$0:$0″\n”}’ a

    方法3:$ sed ‘4~3s/^/\n/’ a

9、字符串拆分

    方法1:

    $ echo “hello” |awk -F ” ‘{for(i=1;i<=NF;i++)print $i}’

    $ echo “hello” |awk -F ” ‘{i=1;while(i<=NF){print $i;i++}}’

    h

    e

    l

    l

    o

    方法2:

    $ echo “hello” |awk ‘{split($0,a,”””);for(i in a)print a[i]}’  #無序

    l

    o

    h

    e

    l

10、統計字符串中每個字母出現的次數

    $ echo a,b.c.a,b.a |tr “[,. ]” “\n” |awk -F ” ‘{for(i=1;i<=NF;i++)a[$i]++}END{for(i in a)print i,a[i]|”sort -k2 -rn”}’

    a 3

    b 2

    c 1

11、第一列排序

    $ awk ‘{a[NR]=$1}END{s=asort(a,b);for(i=1;i<=s;i++){print i,b[i]}}’ a.txt

    說明:以每行編號作為下標值為$1,并將a數組值放到數組b,a下標丟棄,并將asort默認返回值(原a數組長度)賦值給s,使用for循環小于s的行號,從1開始到數組長度打印排序好的數組。

12、刪除重復行,順序不變

    $ awk ‘!a[$0]++’ file


博客地址:http://lizhenliang.blog.51cto.com

QQ群:323779636(Shell/Python運維開發群

13、刪除指定行

    刪除第一行:

    $ awk ‘NR==1{next}{print $0}’ file #$0可省略

    $ awk ‘NR!=1{print}’ file

    $ sed ‘1d’ file

    $ sed -n ‘1!p’ file

14、在指定行前后加一行

    在第二行前一行加txt:

    $ awk ‘NR==2{sub(‘/.*/’,”txt\n&”)}{print}’ a.txt

    $ sed’2s/.*/txt\n&/’ a.txt

    在第二行后一行加txt:

    $ awk ‘NR==2{sub(‘/.*/’,”&\ntxt”)}{print}’ a.txt

    $ sed’2s/.*/&\ntxt/’ a.txt

15、通過IP獲取網卡名

    $ ifconfig |awk -F'[: ]’ ‘/^eth/{nic=$1}/192.168.18.15/{print nic}’

16、浮點數運算(數字46保留小數點)

    $ awk ‘BEGIN{print 46/100}’

    $ awk ‘BEGIN{printf “%.2f\n”,46/100}’

    $ echo 46|awk ‘{print $0/100}’

    $ echo ‘scale=2;46/100’ |bc|sed ‘s/^/0/’

    $ printf “%.2f\n” $(echo “scale=2;46/100” |bc)

    結果:0.46

17、替換換行符為逗號

    $ cat a.txt

    1

    2

    3

    替換后:1,2,3

    方法1:

    $ awk ‘{s=(s?s”,”$0:$0)}END{print s}’ a.txt

    說明:三目運算符(a?b:c),第一個s是變量,s?s”,”$0:$0,第一次處理1時,s變量沒有賦值初值是0,0為假,結果打印1,第二次處理2時,s值是1,為真,結果1,2。以此類推,小括號可以不寫。

    方法2:

    $ tr ‘\n’ ‘,’ < a.txt

    方法3:

    $ sed ‘:a;N;s/\n/,/;$!b a’ a.txt

    說明:第一個標簽a,先讀取第一行記錄1追加到模式空間,此時模式空間內容是1$,執行$!b($!最后一行不跳轉,b是控制流跳轉命令)跳轉到a標簽,繼續讀取第二行記錄2追加到模式空間,因為使用N命令,每個記錄以換行符(\n)分割,此時模式空間內容是1\n2$,執行將換行符替換逗號命令,繼續跳轉到a標簽…

    方法4:

    $ sed ‘:a;$!N;s/\n/,/;t a’ a.txt

    說明:與上面類似,其中t是測試命令,當上一個命令(替換)執行成功才跳轉。

    方法5:

    $ awk ‘{if($0!=3)printf “%s,”,$0;else print $0}’ a.txt

    說明:3是文本最后一個數

    方法6:

    while read line; do

        a+=($line)

    done < a.txt

    echo ${a[*]} |sed ‘s/ /,/g’

    說明:將每行放到數組,然后替換

18、把奇數換行符去掉

    $ cat b.txt

    string

    number

    a

    1

    b

    2

    $ awk ‘ORS=NR%2?”\t”:”\n”‘ b.txt  #把奇數行換行符去掉

    $ xargs -n2 < a.txt  #將兩個字段作為一行

    string number

    a 1

    b 2

19、費用統計

    $ cat a.txt

    姓名             費用   數量

    zhangsan        8000    1

    zhangsan        5000    1

    lisi            1000    1

    lisi            2000    1

    wangwu          1500    1

    zhaoliu         6000    1

    zhaoliu         2000    1

    zhaoliu         3000    1

    統計每人總費用、總數量:

    $ awk ‘{name[$1]++;number[$1]+=$3;money[$1]+=$2}END{for(i in name)print i,number[i],money[i]}’ a.txt

    zhaoliu 3 11000

    zhangsan 2 13000

    wangwu 1 1500

    lisi 2 3000

20、打印乘法口訣

    方法1:

    $ awk ‘BEGIN{for(n=0;n++<9;){for(i=0;i++<n;)printf i”x”n”=”i*n” “;print “”}}’

    1×1=1

    1×2=2 2×2=4

    1×3=3 2×3=6 3×3=9

    1×4=4 2×4=8 3×4=12 4×4=16

    1×5=5 2×5=10 3×5=15 4×5=20 5×5=25

    1×6=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36

    1×7=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49

    1×8=8 2×8=16 3×8=24 4×8=32 5×8=40 6×8=48 7×8=56 8×8=64

    1×9=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81

    方法2:

    #!/bin/bash

    for ((i=1;i<=9;i++)); do

       for ((j=1;j<=i;j++)); do

         result=$(($i*$j))

         #let “result=i*j”

         echo -n “$i*$j=$result “

       done

       echo

    done

21、只打印奇數或偶數行

    打印奇數行:

    方法1:

    $ seq 1 5 |awk ‘i=!i’

    說明:先知道對于數值運算,未定義變量初值為0,對于字符運算,未定義變量初值為空字符串。

    讀取第一行記錄,然后進行模式匹配,i是未定義變量,也就是i=!0,!取反意思。感嘆號右邊是個布爾值,0或空字符串為假,非0或非空字符串為真,!0就是真,因此i=1,條件為真打印第一條記錄。

    沒有print為什么會打印呢?因為模式后面沒有動作,默認會打印整條記錄。

    讀取第二行記錄,進行模式匹配,因為上次i的值由0變成了1,此時就是i=!1,條件為假不打印。

    讀取第三行記錄,因為上次條件為假,i恢復初值為0,繼續打印。以此類推…

    可以看出,運算時并沒有判斷記錄,而是利用布爾值真假判斷。

    方法2:

    $ seq 1 5 |awk ‘NR%2!=0’

    方法3:

    $ seq 1 5 |sed -n ‘1~2p’

    說明:步長,每隔一行打印一次

    方法4:

    $ seq 1 5 |sed -n ‘p;n’

    說明:先打印第一行,執行n命令讀取當前行的下一行2,放到模式空間,后面再沒有打印模式空間行操作,所以只保存不打印,同等方式繼續打印第三行。

    1

    3

    5

    打印偶數行:

    $ seq 1 5 |awk ‘!(i=!i)’

    $ seq 1 5 |awk ‘NR%2==0’

    $ seq 1 5 |sed -n ‘0~2p’

    $ seq 1 5 |sed -n ‘n;p’

    說明:讀取當前行的下一行2,放到模式空間,使用p命令打印模式空間的行,輸出2。

原創文章,作者:cnc,如若轉載,請注明出處:http://www.www58058.com/72981

(1)
cnccnc
上一篇 2017-04-09 18:22
下一篇 2017-04-09 19:34

相關推薦

  • awk學習筆記

        awk是一種模式掃描和處理工具,相對于grep的查找,sed的編輯,它在對數據進行分析生成報表時顯得尤為強大。awk通過逐行遍歷一個或多個文件的方式,查找模式匹配到的行,而后以指定的分隔符(缺省為空格)進行切片,然后針對切片數據進行處理和分析。事實上,gawk有自己的語言,其本身就相當于一個解釋器,允許用戶創建…

    Linux干貨 2015-08-04
  • N22網絡班第一周作業

    1、 描述計算機的組成及其功能。 運算器、控制器、存儲器、輸入設備、輸出設備 運算器、控制器 :cpu 運算和邏輯計算 存儲器:緩存和保存數據 輸入設備、輸出設備:用戶和計算機交互設備和界面 2、 按系列羅列Linux的發行版,并描述不同發行版之間的聯系與區別。 Slackware系列: suse   opensuse debian系列: ubun…

    Linux干貨 2016-08-15
  • LVM邏輯卷管理練習

         小編今天要講的內容是如何創建邏輯卷,然后擴展它、縮減它。LVM 的重點就在于可以彈性的調整文件系統的容量!所以,下面練習開始。 1、創建一個至少有兩個PV組成的大小為20G的名為testvg的 VG;要求PE大小為16MB, 而后在卷組中創建大小為5G的邏 輯卷testlv;掛載至/users目錄。 ①準備兩個10G的…

    2017-08-26
  • 基于LNMP架構添加Memcached支持,并驗證其緩存結果

    一 Memcached簡介 Memcached是一個自由開源的,高性能,分布式內存對象緩存系統。它是一種基于內存的key-value存儲,用來存儲小塊的任意數據(字符串、對象)。這些數據可以是數據庫調用、API調用或者是頁面渲染的結果。 Memcached簡潔而強大。它的簡潔設計便于快速開發,減輕開發難度,解決了大數據量緩存的很多問題。它的API兼容大部分流…

    Linux干貨 2016-12-12
  • Linux之sed的使用

    sed的工作原理         sed是一種流編輯器以行為單位來處理文本的一款功能十分強大的編輯器,一次只處理一行內容,當處理文本是,將要處理的行放置在模式空間里(緩沖區),接下來sed命令處理模式空間里的內容,處理完成后,把模式空間里處理后的內容送至屏幕打印輸出,接下來處理下…

    Linux干貨 2016-08-09
  • ![](http://i1.pixiv.net/img-original/img/2016/08/09/20/23/25/58345400_p0.jpg) ![](http://i1.pixiv.net/img-original/img/2016/08/09/20/23/25/58345400_p0.jpg)

    Linux干貨 2016-12-26
欧美性久久久久