awk詳解

一、awk簡介

   awk的意思是報告生成器,能根據輸入信息,把信息格式化後顯示,繼而出現new awk(nawk)在windows上實現,gawk,awk實現在linux上。awk是一種編程語言,在linux/unix下對文本和數據進行處理,是一款強大編程工具。在命令行中使用,更多作爲腳本來使用。

   awk處理文件和數據的方式:逐行掃描文件,從第一行到最後一行,尋找匹配的特定模式的行,並在這些行上進行操作。如果沒有指定處理動作,則把匹配行打印,如果沒有指定模式,則所有行都處理。gawk是awk的GNU版本。可通過命令ll `which awk`查看

   Linux文本處理三劍客:

    grep, egrep, fgrep: 文本過濾器

    sed: 文本編輯(行編輯器) 

    awk: 文本格式化,報表生成器   

 awk工作過程

   根據定義的模式,一次從文本中讀取一行,awk會對行做相應的切片,將每一行按照分割符進行切割。例如this is a test 使用空白字符做分隔符將它們分開,切割爲this,is,a,test四個片,可以使用變量,分別對應爲$1,$2,$3,$4代表四個切割片  

二、awk用法 

 1、基本格式 

   gawk [options] 'program' file file ...

        program程序: PATTERN { ACTION STATEMENT }

          由語句組成,語句分隔符是";"          

        ACTION: print, printf 

    選項options:

      -F[]:指明輸入字段分隔符;默認以空白爲分隔符

          -F[, ]:逗號或空格爲分隔符

      -v var=val: 變量賦值,無須聲明,可直接調用

      -f /path/from/awk_script

  EX: 

   (1)、打印/etc/passwd中的第三行和第六行不同用法

    #awk -F: '{print $3,$6}' /etc/passwd 
    #awk -F: -v f1=3 -v f2=6 '{print $f1,$f2}' /etc/passwd  
    #awk -v FS=':' '{print $3,$6}' /etc/passwd

   (2)、運行awk腳本  

    #vim awk.script
     {print $1,$3}
    #awk -f awk.script -F: /etc/passwd

 2、awk的輸出命令print    

    print item1, item2, ...

      item:

       (1)字符串:用引導引用

          print "htello","world"

       (2)變量:顯示變量的值

          print name

     要點:

        (1)item間用逗號,輸出爲空白字符

        (2)item可以爲字符串、變量、數值等

        (3)item如果省略,等於print $0

        (4)輸出空白字符,print ""

    EX:打印/etc/passwd中的所有用戶   

    #awk -F: '{print  "user is",$1}' /etc/passwd

 3、變量      

  3.1 內置變量

  (1)FS: input field seperator,輸入字段分隔符,默認爲空白字符;

    #awk -v FS=":" '{print $1,$3}' /etc/passwd
    #vim awk.txt
    This is the first line.
    Here you are.
    This is tomas,jason.
    #awk '{print $3}' awk.txt
    #awk -v FS="[ ,]" '{print $3}' awk.txt  //輸出以逗號或空白字符爲分隔符的字段

  (2)RS:input record separator,輸入行分隔符 默認爲換行符; 

  #awk -v RS=" " '{print $0}' /etc/passwd

  (3)OFS: output field separator,輸出字段分隔符,默認爲空白字符;  

 #awk -v FS=":" -v OFS=":" '{print $1,$3,$7}' /etc/passwd  //輸出字段分隔符也爲":"

  (4)ORS:output record separator,輸出行分隔符, 默認爲換行符;

  #awk -v RS=" " -v ORS=" " '{print $0}' /etc/passwd

  (5)NF: number of field in current  record,當前行的字段數;

  #awk '{print NF}' /etc/issue  //打印行數
  #awk '{print $NF}' /etc/issue  //打印行最後字段

  (6)NR:行數,所有文件統一計數;   

 #awk '{print NR}' /etc/issue

  (7)FNR:行數,各文件分別計數;  

 #awk '{print FNR}' /etc/fstab /etc/issue

  (8)FILENAME:當前被讀取的文件名   

 #awk '{print NR,FILENAME}' /etc/issue

  (9)ARGC:命令行參數的個數;   

#awk '{print ARGC}' /etc/issue   //這裏顯示爲兩個參數,包括print和文件名

  (10)ARGV:數組,保存了命令行參數自身 

 #awk '{print ARGV[0]}' /etc/issue  //參數爲print和文件名,但是輸出ARGV[0],則顯示爲awk

 3.2 自定義變量

  -v var=val: 

    變量名命名規則:

      區分字符大小寫

      數字,字符,下劃線,不能以數字開頭

      不能使用內置關鍵字   

    定義變量的位置:

      (1) 可以program中定義變量;

      (2) 通過-v選項定義變量;

    #awk 'BEGIN{FS=":";f1=1}{print $f1}' /etc/passwd  //只在開始賦值一次     
    #awk -F: '{f1=1;print $f1}' /etc/passwd  //每行都要賦值

4、printf命令      

    格式: printf format, item1, item2, ...

    (1)要點:

        (1) format是必須的;

        (2) 不自動換行,需給換行符;\n

        (3) 爲每個item指定格式符;否則item無法顯示        

    (2)格式符:都以%開頭,後跟一個字符

        %c: 顯示字符的ASCII碼;

        %d,%i: 顯示十進制整數;

        %e, %E: 科學計數法顯示數值;

        %f: 顯示爲浮點數;

        %g, %G: 以科學計數法格式或浮點數格式顯示數值;

        %s: 字符串

        %u: 無符號的整數

        %%: 顯示%自身  

 #awk -F: '{printf "This is user: %s.\n",$1}' /etc/passwd   
 #awk -F: '{printf "This is user: %s,his UID is %d.\n",$1,$3}' /etc/passwd

    (3)修飾符:

        #[.#]: 第一個#指定顯示寬度,例如%30s;第二個#表示小數點後的精度;

        -: 左對齊,默認爲右對齊

        +:顯示數值符號

 #awk -F: '{printf "This is user: %s,his UID is %-20f.\n",$1,$3}' /etc/passwd  //UID顯示爲20個字符並且精度爲2  
 #awk -F: '{printf "%20s:%-d\n",$1,$3}' /etc/passwd

 5、操作符:

  (1)算術操作符:

    x+y, x-y, x*y, x/y, x^y, x%y

    -x: 負值

    +x: 轉換爲數值

    #awk 'BEGIN{print 4*5}' 

  (2)字符串操作:字符串連接

    #awk ‘BEGIN{print "hello" "awk"}’

  (3)賦值操作符:

     =, +=, -=, *=,  /=,  %=, ^=

     ++, --

  #awk -v f1=3 'BEGIN{f1*=6;print f1}'

  (4)比較操作符:

     >, >=, <. <=, ==, !=       

  (5)模式匹配符:

     ~:能匹配爲真

     !~:不能匹配爲真       

  (6)邏輯操作符:

     && 與運算

     || 或運算       

  (7)條件表達式:

  selector?if-true-expression:if-false-expression

    相當於bash的:

     if SELECTOR;then

        if-true-expression

      else

        if-false-expression

  # awk -F: '{$3>=500?usertype="common user":usertype="sysuser or admin";printf "%20s:%-s\n",$1,usertype}' /etc/passwd
  #df -h | awk '{printf "%30s:%-s\n",$1,$5}'

  (8)函數調用:

    function_name(argu1,argu2,...)        

 6、PATTERN     

    (1) /regular expression/: 正則表達式,僅處理能夠被/regular expression/所匹配到的行;   

 #awk -F: '/^[ab]/{print $1,$3}' /etc/passwd

    (2) relational expression:關係表達式,有真假之分,一般來說,其結果爲非0或非空字符串時爲“真”,否則,爲“假”;   

#awk -F: '$3>=500{print $1,$3}' /etc/passwd  //打印UID大於和等於500的用戶名和UID
#awk -F: '$1~/root/{print $1,$3}'  /etc/passwd   //打印用戶名包含root的用戶名和UID

    (3) line ranges:行範圍,類似sed或vim的地址定界法;startline, endline

    (4) BEGIN/END: 特殊模式

    BEGIN:程序執行前執行一次

    END:程序執行後執行一次  

 #awk -F: 'BEGIN{printf "%20s:%-s\n","UserName","UserID"}{printf "%20s:%-d\n",$1,$3}END{print "--------\nprogram is end"}'  /etc/passwd  
 #awk 'BEGIN{FS=":"}{print $1,$3}' /etc/passwd

    (5) empty: 空模式,匹配任意行;   

 #awk -F: '{print $1,$NF}' /etc/passwd

  7、常用的action     

    (1) Expressions  表達式,如變量賦值

    (2) Control statements  控制語句,如if,while等

    (3) Compound statements  複合語句,如{}

    (4) input statements  輸入語句

    (5) output statements  輸出語句   

  8、控制語句     

    if (condition條件) { statement語句 } [ else statement ]

    while (condition) { statement }

    do statement while (condition)

    for (expr1初值; expr2循環; expr3修正) statement

    for (var in array) statement

    switch (expression) {case VALUE or /REGEXP/:statement;...;default;statement}

    break  結束循環

    continue  結束本輪循環

    delete array[index]

    delete array

    exit [ expression ]

    { statements }     

  8.1 if-else        

     語法:if (condition條件) statement [ else statement ] 

           if (condition) { statements; } [ else { statements; }]               

 # awk -F: '{if ($3>=500) print $1," is a common user." }' /etc/passwd
 # awk -F: '{if ($3>=500) {print $1," is a common user."} else {print $1," is a system user or admin."}}' /etc/passwd
 # awk '{if (NF>6) print NF, $0 }' /etc/inittab

   用法:對awk取得的整行或行中的字段做條件判斷;       

  8.2 while循環

   語法:while (condition) statement

        while (condition) { statements }

        條件爲真時進行循環,直到爲假退出;          

      用法:通常用於在當前行的各字段間進行循環;             

 # awk '{i=1;while(i<=NF){printf "%20s:%d\n",$i,length($i); i++}}' /etc/inittab   //打印每行字段名稱和字段長度
 # awk '{i=1;while(i<=NF){if (length($i)>5) {printf "%20s:%d\n",$i,length($i);} i++}}' /etc/inittab  //查找打印在文件/etc/inittab下每行字段長度大於5的字段名稱和長度

  8.3 do-while循環  瞭解

      語法:do statement while (condition)

        do { do-while-body }  while (condition)

        意義:至少執行一次循環體;        

  8.4 for循環

    語法:for (expr1; expr2; expr3) statement

      for (expr1; expr2; expr3) { statements }          

      for (varaiable assignment; condition; iteration process) { for-body }    

#awk '{for(i=1;i<=NF;i++){if(length($i)>=6) print $i}}' /etc/issue  //查找文件/etc/issue字段長度大於等於6並打印字段
#awk '{for(i=1;i<=NF;i++) {printf "%s:%d\n", $i, length($i)}}' /etc/inittab

    for循環在awk中有一個專用於遍歷數組元素:

      語法:for (var in array) { for-body }          

  8.5 switch 瞭解

      語法:switch (expression) {case VALUE or /REGEXP/: statement; ...; default: statementN}          

  8.6 break and continue

        break [n]: 退出當前循環,n表示幾層循環

        continue:提前結束本輪循環,直接進入下輪循環       

  8.7 next

       提前結束對本行的處理而進入下一行的處理               

 # awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd   //打印UID爲奇數的行的1和3字段,對UID取模,如果等於0則執行next進入對下一行的處理,如果不等於0則執行一條語句打印$1和$3字段

 9、Array 數組     

    關聯數組:array[index-expression]     

      index-expression: 索引表達式

        可以使用任意字符串;

        如果某數組元素事先不存在,在引用時,awk會自動創建此元素並將其值初始化爲空串;

           因此,若要判斷數組是否存在某元素,要使用“index in array”進行;     

      要遍歷數組中的每個元素,要使用: for (var in array) ,var會遍歷array的每個索引,所以,要顯示數組元素的值,要使用array[var]

     weekdays

        weekdays[mon]="Monday"

        weekdays[tue]="tuesday"

        ...

      for(i in weekdays) 此時i會遍歷weekdays數組的每個索引,即mon,tue,而非元素的值"Monday"或"Tuesday"等

      要獲取元素的值:weekdays[i]             

   EX:統計每一行中各單詞分別出現的次數

      可定義一個數組,用單詞本身當索引,而元素的值存儲單詞出現的次數     

# awk '{for(i=1;i<=NF;i++) {count[$i]++}}END{for(j in count) {print j,count[j]}}' awk.txt  //統計文本中每個單詞及出現的次數,第一個for定義數組,第二個for遍歷數組
# awk '{for(i=1;i<=NF;i++) {count[$i]++}}END{for(j in count) {print j,count[j]};delete count}' awk.txt //分別統計每行每個單詞及出現的次數         
# ss -tan | awk '!/^State/{state[$1]++}END{for (i in state) {print i,state[i]}}'   //統計TCP連接各狀態名稱及個數
#awk '{ip[$1]++}END{for(i in ip)print i,ip[i]}' /var/log/httpd/access_log  //統計web被訪問的IP及次數
# netstat -tan | awk '/^tcp/{state[$NF]++}END{for(i in state){print i,state[i]}}

 10、函數      

  (1)內置函數

    1)數值處理:

        rand(): 返回0和1之間一個隨機數;    

#awk 'BEGIN{print rand()}'

    2)字符串處理:

        ength([s]): 返回指定字符串的長度  

#awk 'BEGIN{print length("hello")}'

    3)sub(r, s [, t])查找r在t中,把每行第一次出現的r替換爲s

        sub(ab,AB,$0)    

#vim count.txt
How are you? How old are you?
#awk '{sub("are","ARE",$0);print $0}' count.txt

    4)gsub(r, s [, t]):查找r在t中,把所有出現的r替換爲s

    5)split(s, a [, r]): 以r爲分隔符,s爲字符串切割,並把結果保存到a中

      注意:awk的數組下標從1開始編號     

#awk '{split($0,userinfo,":");print userinfo[1]}' /etc/passwd   //以":"爲分隔符,$0爲字符串切割,並把結果保存到userinfo中         
# netstat -tan | awk '/^tcp/{len=split($5,client,":");ip[client[len-1]]++}END{for(i in ip){print i,ip[i]}}'

    6)substr(s, i [, n]): 從s表示的字符串中取子串,從i開始,取n個字符;        

    7)時間類的函數:

        systime(): 取時間戳;       

    8)位運算函數:

        and(v1,va2):          

  (2)自定義函數

        function f_name(p,q) 

        {

          ...

        }



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章