文本處理三劍客之awk

文本處理三劍客:grep系,sed,awk
grep系:grep,egrep,fgrep,基於PATTERN進行文本過濾;
sed:流編輯器,逐行編輯器;模式空間,保持空間;
awk:報告生成器;格式化文檔輸出;html

下面是三劍客其中之一的awk:linux

awk:其實就是gawk,是一種模式掃描和處理語言(Centos系/RHEL系中是通過GNU從新編寫過的awk叫作gawk);
格式:gawk [ options ] 'program' file ...
program:[/PATTERN/]{ACTION statement;...} //只能有一對單引號,只能在program兩側
PATTERN部分:決定動做語句什麼時候觸發以及經過什麼事件來觸發;
BEGIN,END
注意:在有BEGIN語句塊的前提下,後面的file有時候能夠省略;
ACTION statement:對數據進行特定的處理,一般放置在{}中,並使用單引號進行引用;web

基本概念:
        分隔符:
            輸入分隔符:awk對數據進行處理時,會根據特定的符號對數據進行分段處理,這種標識符號就稱爲「輸入分隔符」,默認的輸入分隔符是空白字符;若是指定的分隔符並無被數據包括,則只有換行分隔符有效;
            輸出分隔符:awk對數據處理完成後,會以特定的標識符號對各個字段進行鏈接後輸出,這種標識符號就稱爲「輸出分隔符」,默認的輸出分隔符是空白字符;
        記錄:由換行符進行分隔的數據中的一行,就稱爲一條記錄(record);一般在使用awk處理數據時,使用$0來保存整個記錄的內容;
        字段:通過分隔符分隔以後的每個數據分段,都稱爲一個字段(field);一般在使用awk處理數據時,使用$1,$2,...$NF等內置變量來存儲各個字段的數據;

awk的工做原理:
    1.首先,執行BEGIN{ACTION statement;...}語句塊中的語句;
    2.其次,從文件中或者標準輸入讀取一行,再根據PATTERN的匹配結果執行後面的ACTION語句塊中的內容;而後逐行重複該過程以完成數據處理,直至數據所有被讀取完畢;
    3.最後,再全部的語句塊都執行完成以後,退出awk進程以前,執行END{ACTION statement;...}語句塊中的語句;
    注意:
        1)BEGIN語句塊在awk開會處理數據內容以前就被執行;一般用於生成表頭;此語句塊是可選語句塊;
        2)END語句塊在處理完全部的數據以後,纔會被執行;一般用於數據彙總;此語句塊是可選語句塊;
        3)PATTERN語句塊中的通用命令是最重要的部分,所以PATTERN語句塊不能省略,但其中的ACTION能夠省略,若是省略,則默認執行print動做,即:顯示數據的各行;
        4)awk在執行PATTERN語句塊時,默認循環遍歷數據彙總的各個記錄;

經常使用選項:
    -f,--file program-file:從指定的文件中加載program語句塊,而不是經過命令行給出相關的程序內容;
    -F,--field-separator fs:指定字段的輸入分隔符;默認是空白字符;
    -v,--assign var=value:用於聲明自定義變量或數組併爲變量賦值;//能夠在BEGIN、PATTERN和END語句塊中自定義變量,也能夠聲明數組;在選項當中每定義一個變量都須要再書寫一次"-v"

awk的經常使用用法:
    1.變量:
        內建變量:
            FS:輸入字段分隔符,默認是空白字符;
            OFS:輸出字段分隔符,默認的是空白字符;
                示例:
                    ~]# awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd  //顯示當前系統內存在用戶的用戶名、用戶的uid、用戶默認的shell(用「:」輸入分隔,使用「:」輸出分隔)
                    root:0:/bin/bash
                    bin:1:/sbin/nologin
                    daemon:2:/sbin/nologin
            RS:輸入記錄(行)分隔符,默認爲換行符;  //換行符仍是生效的
            ORS:輸出記錄分隔符,默認爲換行符;  //awk認爲的換行符,真正輸出換行的仍是原有的換行符
                示例:
                ~]# awk -v RS=':' -v ORS='#' '{print $0}' /etc/passwd
                root#x#0#0#root#/root#/bin/bash
                bin#x#1#1#bin#/bin#/sbin/nologin
            NF:每一行當中字段的總數;
                示例:
                ~]# awk -F: '{print NF}' /etc/passwd  //顯示指定文件中每行中的字段的數量
                7
                ...
                ~]# awk -F: '{print $NF}' /etc/passwd  //顯示指定文件中每行中最後一個字段的內容
                /bin/bash
                /sbin/nologin
                ... 
                ~]# awk -F: '{print $(NF-1)}' /etc/passwd  //顯示指定文件中每行中倒數第二個字段的內容
                /root
                /bin    
                ...
            NR:行的總數;若是僅處理一個文件,能夠將NR的值當作文件中各行的行號;
                示例:
                    ~]# awk '{print NR}' /etc/fstab  //顯示一個文件的行數,處理單個文件時,能夠記作行數
                    1
                    2
                    3
                    ...
            FNR:對於不一樣的文件分別統計其行的數量;即便處理多個文件,也能夠顯示每一個文件中的行號;
                示例:
                    ~]# awk '{print FNR}' /etc/fstab /etc/issue //處理多個文件,顯示每一個文件中的行號
            FILENAME:當前正在被處理的文件的文件名;
                示例:
                ~]# awk 'END{print FILENAME}' /etc/passwd 
                /etc/fstab
            ARGC:命令行中參數的數量;包括awk命令自己但不包括awk選項部分也不包括program部分;
                示例:
                ~]# awk 'END{print ARGC}' /etc/fstab /etc/issue /etc/passwd
                4
            AGRV:由命令行中全部的參數構成的數組;AGRV[0]:顯示參數構成數組中的第一個參數awk;
                示例:~]# awk 'END{print ARGV[1]}' /etc/fstab /etc/issue /etc/passwd  //顯示命令行中的第N個參數
                      /etc/fstab

        自定義變量:
            定義方式:-v var_name=value (變量字母嚴格區分大小寫)
                示例:
                ~]# awk -v var='hello' -F: '{print var","$1}' /etc/passwd  //對當前系統內的用戶打招呼:「hello,User」
                hello,root
                hello,bin

awk經常使用的ACTION:
    2.print:以標準格式輸出文檔;
        格式:
            print item1,item2,...
                示例:
                ~]# awk '{print}' /etc/issue
                CentOS release 6.7 (Final)
                Kernel \r on an \m
                ~]# awk '{print $1,$3,$NF}' /etc/issue
                CentOS 6.7 (Final)
                Kernel on \m
            注意:
                1)各個元素之間須要使用「,」進行分隔;
                2)輸出的各item能夠是字符串,能夠是數字,能夠是當前記錄中的字段,能夠是變量,能夠是awk的表達式;
                3)若是省略了item,則默認的是item爲$0,即:輸出整行;
    3.printf:以特定的格式輸出結果;
        格式:
            printf "FORMAT" item1,item2,...
                示例:
                    ~]# awk -F: '{printf "%20s:%-+5d\n",$1,$3}' /etc/passwd
                                    root:+0   
                                    bin:+1   
                                    daemon:+2 
            注意:
                1)必須給出合適的輸出格式;
                2)默認不會自動換行,若是想要在輸出結果中換行顯示的話須要明確的給出換行控制符「\n」;
                3)FORMAT中須要爲後面的每個item單獨指定一個格式化符號;
            經常使用的FORMAT:
                %c:以ASCII碼中的內容顯示字符信息;
                %d,%i:顯示十進制整數;
                %e,%E:以科學計數法來顯示數字(浮點類型1.2,1.3,...);//類似:%g,%G:以科學計數法顯示浮點數字
                %f,%F:顯示十進制數字的浮點形式;

                %u:無符號的十進制數;
                %o:無符號的八進制數;
                %s:顯示字符串;
                %x,%X:顯示無符號的十六進制數;
                %%:顯示一個「%」符號;
            修飾符:
                #[.#]:第一個數字用來控制顯示寬度;第二個數字表示小數點後的精度;
                -:表示採用左對齊方式顯示,默認是右對齊;
                +:顯示數字的正負符號;(若是不是數字沒有意義)
    4.操做符:
        算數運算操做符:(雙目運算符優先級低於單目運算符)
            雙目運算符:x+y,x-y,x*y,x/y(y不能爲0),x^y(優先級最高),x%y
            單目運算符:
                -x:將正整數轉換爲負整數;
                +x:將字符串轉換爲數值;
            示例:~]# awk -F : 'END{print 100^2}' /etc/passwd
        字符串操做符:
            無任何操做符號,即爲字符串鏈接操做;
        賦值操做符:
            =,+=,-=,*=,/=,^=,%=
            ++,--(步長爲1)
        比較操做符:
            ==,!=,>,<,>=,<=
                示例:
                    [root@chenliang ~]# awk -F: '$3==0{print $1}' /etc/passwd  //取出系統中用戶uid爲0的用戶
                    root
        模式匹配操做符:
            ~:操做符左側的字符串是否可以被右側的模式PATTERN所匹配;
            !~:操做符左側的字符串是否不可以被右側的模式PATTERN所匹配;
                示例:
                ~]# awk -F : '$NF~/bash/{print $0}' /etc/passwd  //取出系統中shell爲bash的用戶
        邏輯運算操做符:&&  || !
                示例:
                    ~]# awk -F: '$3>=100&&$3<=1100{print $0}' /etc/passwd  //取出系統中用戶uid大於等於100且小於等於1100的用戶
                    usbmuxd
                    rtkit
        條件表達式:
            selector(condition)?if-true-expression:if-false-expression
                示例:
                    ~]# awk -F: '{$3>=1000?usertype="Common User":usertype="SuperUser or Sysuser";printf "%20s: %-20s\n",usertype,$1}' /etc/passwd   //系統中用戶uid大於等於1000就標記爲Common User,不然標記爲SuperUser or Sysuser
                    Super or Systemuser: root                
                    Super or Systemuser: bin
    5.PATTERN(模式)部分:
        1)empty:空模式,不加區分的處理文件的每一行;
        2)[!]/REGEXP/:僅處理[不]能被PATTERN匹配到的每一行;
            示例:~]# awk -F: '!(/^r/)&&/n$/{print $1}' /etc/passwd  //取出系統中非r開頭且不以n結尾的用戶名
                  bin:x:1:1:bin:/bin:/sbin/nologin
        3)關係表達式:
            示例: ~]# awk -F: '{$3>=1000?usertype="Common User":usertype="SuperUser or Sysuser";printf "%20s: %-20s\n",usertype,$1}' /etc/passwd   //系統中用戶uid大於等於1000就標記爲Common User,不然標記爲SuperUser or Sysuser
                    Super or Systemuser: root                
                    Super or Systemuser: bin
        4)行域,行範圍:
            關係表達式的邏輯運算:FNR>=10&&FNR<=20
                示例:
                    ~]# awk -F: 'FNR>=12&&FNR<=14{print $1}' /etc/passwd  //取出/etc/passwd中12到14行的用戶名
                    games
                    gopher
                    ftp
            /REGEXP1/,/REGEXP2/:從被REGEXP1匹配的行開始,直到被REGEXP2匹配的行結束,這期間的全部行;凡是屬於此類的匹配結果,有多少組就顯示多少組;
                示例:
                    ~]# awk -F: '/^n/,/^c/{print $1}' /etc/passwd  //取出/etc/passwd中從n開頭到c開頭爲用戶名的用戶名
                    nobody
                    nfsnobody
                    ntp
                    cl1
        5)BEGIN/END模式:
            BEGIN{}:僅在開始處理文件中第一行文本數據以前執行一次的語句塊;多用於輸出特定格式的表頭信息;
                示例:
                    ~]# awk -F: 'BEGIN{printf "%20s %10s %20s\n","USERNAME","USEUID","SHELL"}NR>=15&&NR<=20{printf "%20s %10s %20s\n",$1,$3,$7}' /etc/passwd   //在文件/etc/passwd中顯示USERNAME ,USERUID ,SHELL爲表頭的15到20行的用戶信息
                    USERNAME    USERUID                SHELL
                      nobody         99        /sbin/nologin
                        dbus         81        /sbin/nologin
                     usbmuxd        113        /sbin/nologin
                        vcsa         69        /sbin/nologin
                         rpc         32        /sbin/nologin
                       rtkit        499        /sbin/nologin
            END{}:僅在文本處理完成但awk命令還沒有退出時執行一次的語句塊;多用於數據信息的彙總;
                示例:
                    ~]# awk -F: 'BEGIN{printf "%20s %10s %20s\n","USERNAME","USERID","SHELL"}NR>=15&&NR<=20{printf "%20s %10s %20s\n",$1,$3,$7}END{print "----------------------------------------\n",NR " users"}' /etc/passwd
            注意:
                1)BEGIN語句塊,PATTERN語句塊,END語句塊的順序,一般的書寫順序爲:BEGIN{}PATTERN{}END{};
                2)BEGIN語句塊和END語句塊是可選的,但PATTERN語句塊必需要寫;
        6)經常使用的ACTIONS
            1.表達式
            2.組合語句
            3.輸入語句
            4.輸出語句
            5.控制語句
        7)控制語句:
            (1)if ... else:
                語法:if (condition) statement [ else statement ]
                使用場景:對awk取得的整行或某個字段作條件判斷;
                    示例:
                        ~]# awk -F: '{if($3>=1000){print $1}else{print "Username: ",$1}}' /etc/passwd  //uid大於等於1000的用戶,若是不符合條件的用戶就在用戶名簽名標識「Username: 」字樣
                        Username:  root
                        Username:  bin
                        ~]# awk '/^[^#]/{if(NF==6){print}}' /etc/fstab   //輸出/etc/fstab文件中非#號開頭的以空白字符分隔的含有6個字段的行
                        /dev/mapper/vg_chenliang-lv_root /                       ext4    defaults        1 1
                        UUID=ceeb9f75-73ea-412f-a33a-1704433e538b /boot                   ext4    defaults        1 2
                        /dev/mapper/vg_chenliang-lv_swap swap                    swap    defaults        0 0
                        tmpfs                   /dev/shm                tmpfs   defaults        0 0
                        devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
                        sysfs                   /sys                    sysfs   defaults        0 0
                        proc                    /proc                   proc    defaults        0 0

                        分析磁盤上各個文件系統的空間利用率:
                            ~]# df -h | awk -F% '/^\/dev/{print $1}' | awk '{if($NF>=80){print $1}}'
                            9
            (2)while循環:
                語法:while (condition) statement
                使用場景:
                    a.對一行內的多個字段逐一作相同或相似的操做處理時使用;
                    b.對數組中的各數組元素作遍歷處理時使用;
                while循環的特定:條件爲真,進入循環;一旦條件爲假,則退出循環;
                    示例:
                        ~]# vim testfile
                        Hello! My Linux World! Let's go ~
                        ~]# awk '{i=1;while(i<=NF){print $i,length($i);i++}}' testfile  //判斷testfile中以空白字符分隔的每一個字段的字符數
                        Hello! 6
                        My 2
                        Linux 5
                        World! 6
                        Let's 5
                        go 2
                        ~ 1
            (3)do ... while語句:
                語法:do statement while (condition) //意義:與while循環相同,但statement語句段至少被執行一次;
                    示例:
                        ~]# awk '{do{print $i,length($i);i++}while(i<=NF)}' testfile  //判斷testfile中以空白字符分隔的每一個字段的字符數
                        Hello! My Linux World! Let's go ~ 33
                        Hello! 6
                        My 2
                        Linux 5
                        World! 6
                        Let's 5
                        go 2
                        ~ 1
            (4)for循環:
                語法:
                    for (expr1; expr2; expr3) statement //第一種語法
                        expr1:變量賦初始值;
                        expr2:循環條件判斷;
                        expr3:變量值的迭代處理(變量值修正方法);
                            示例:
                                ~]# awk '{for(i=1;i<=NF;i++){print $i,length($i)}}' testfile  //判斷testfile中以空白字符分隔的每一個字段的字符數
                                Hello! 6
                                My 2
                                Linux 5
                                World! 6
                                Let's 5
                                go 2
                                ~ 1
                    for (var in array) statement //第二種語法
                        示例:
                            awk -F: '$NF!~/^$/{BASH[$NF]++}END{for(i in BASH){printf "%15s:%i\n",i,BASH[i]}}' /etc/passwd
                            /sbin/shutdown:1
                                 /bin/bash:2
                            /sbin/nologin:29
                                /sbin/halt:1
                                 /bin/sync:1

            (5)switch ... case語句:
                語法:switch (expression) { case value1|regex1:statement;case value2|regex2:statement; ... [ default: statement ]}
                使用場景:用於字符串比較判斷;
            (6)break語句和continue語句:
                break [n]
                    示例:
                        [root@chenliang ~]# awk '{for(i=1;i<=NF;i++){if(length($i)<5){break}{print $i,length($i)}}}' testfile 
                        Hello! 6
                continue
                注意:其使用場景是行內多個字段間作循環時的循環控制方式;
                    示例:
                        ~]# awk '{for(i=1;i<=NF;i++){if(length($i)<5){continue}else{print $i,length($i)}}}' testfile
                        Hello! 6
                        Linux 5
                        World! 6
                        Let's 5

            (7)next語句:
                在awk處理數據時,提早結束對當前行的處理,而直接開始處理下一行;
                    示例:
                        ~]# awk -F: '{if($3%2==1){next}else{print $1,$3}}' /etc/passwd
                        root 0
                        ~]# awk -F: '{if($3%2==1)next;print $1,$3}' /etc/passwd
                        root 0
            (8)數組——Array
                用戶自定義的數組,通常使用關聯數字:array_name[index_expression]
                    注意:
                        1)index_expression可使用任意的字符串,但字符串必需要放在雙引號中;
                        2)支持弱變量數組,即:若是某數組元素事先不存在,當引用該元素時,awk會自動建立此元素,併爲此元素賦「空字符串」做爲其初始值;
                            示例:                                 
                                1.[root@chenliang ~]# awk 'BEGIN{name["leader"]="zhangsan";name["mem1"]="lisi";name["mem2"]="wangwu";print "Leader: ",name["leader"],"\nMember: ",name["mem1"],name["mem2"]}'
                                Leader:  zhangsan 
                                Member:  lisi wangwu
                                2.[root@chenliang ~]# awk 'BEGIN{name["leader"]="zhangsan";name["mem1"]="lisi";name["mem2"]="wangwu";for(i in name){print name[i]}}'
                                wangwu
                                zhangsan
                                lisi
                                3.查看當前系統上全部服務的不一樣TCP狀態的鏈接數量的統計;
                                    ~]# netstat -nalt | awk '/^tcp\>/{state[$NF]++}END{for(stat in state){printf "%15s: %-10d\n",stat,state[stat]}}'
                                    ESTABLISHED: 1         
                                    LISTEN: 10
                                4.用於統計本服務器web站點的每一個用戶的請求數值:
                                    ~]# awk '{ipaddr[$1]++}END{for(ip in ipaddr){print ip,ipaddr[ip]}}' /var/log/httpd/access_log   
                                    172.16.0.1 3
                                    172.16.74.1 3
                                5.用於統計本服務器web站點的UV值(訪問量):
                                    ~]# awk '{ipaddr[$1]++}END{for(ip in ipaddr){print ip,ipaddr[ip]}}' /var/log/httpd/access_log | wc -l
            (9)函數:
                內建函數:
                    數值函數:
                        rand():返回一個介於0-1之間的隨機數;
                            示例:
                                [root@chenliang ~]# awk 'BEGIN{print rand() }'
                                0.237788
                        sqrt():對於指定的數值進行開二次方;
                            示例:
                                [root@chenliang ~]# awk 'BEGIN{print sqrt(5) }'
                                2.23607
                    字符串函數:
                        length():計算給定字符串的長度;
                            示例:
                                [root@chenliang ~]# awk 'BEGIN{print length(123456789) }'
                                9
                        gsub(r, s [, t]):以r表示的模式來查找t表示的字符串中可以被匹配的內容,並將全部出現的內容替換成s表示的內容;
                            示例:
                                ~]# awk 'BEGIN{filed="This is a test text !";gsub(/text/,"file",filed);print filed}'
                                This is a test file !

                        split(s, a [, r [, seps] ]):以seps做爲分隔符,利用r表示的模式進行匹配,將s表明的字符串分割以後,保存在a表示的數組之中;
                            示例:
                                示例1~]# awk 'BEGIN{demo="learning linux is very happy ~";split(demo,DEMO," ");for(i in DEMO){print i,DEMO[i]}}'
                                4 very
                                5 happy
                                6 ~
                                1 learning
                                2 linux
                                3 is
                                示例2~]# awk 'BEGIN{print split("123#456#678", myarray, "#")}'
                                3

                自定義函數:
                    在命令行中自定義函數:function name(parameter list) { statements }
                    在腳本中自定義函數:
                        function 函數名(參數表){ 
                        函數體 
                        } 
                        function  f(p, q,     a, b)   # a and b are local
                        {
                            ...
                        }

                    示例:
                        寫兩個函數計算最小和最大數,從main函數中調用這些函數(自定義函數示例轉自http://www.yiibai.com/awk/awk_user_definede_functions.html):
                        # Returns minimum number
                        function find_min(num1, num2)
                        {
                          if (num1 < num2)
                            return num1
                          return num2
                        }

                        # Returns maximum number
                        function find_max(num1, num2)
                        {
                          if (num1 > num2)
                            return num1
                          return num2
                        }

                        # Main function
                        function main(num1, num2)
                        {
                          # Find minimum number
                          result = find_min(10, 20)
                          print "Minimum =", result

                          # Find maximum number
                          result = find_max(10, 20)
                          print "Maximum =", result
                        }

                        # Script execution starts here
                        BEGIN {
                          main(10, 20)
                        }

                        在執行上面的代碼後,會獲得以下結果:
                        Minimum = 10
                        Maximum = 20
相關文章
相關標籤/搜索