awk進階詳解

    文本三工具grep sed awk
    grep  egrep  fgrep 文本過濾
    sed  行編輯器
        模式空間、保持空間
    awk 報告生成器,格式化文本輸出

    AKW: Aho,Weinberger,Kernighan  這個工具的三個人的作者
            1970s出現的-->New AWK ,NAWK

    
    linux上用的是GNU awk 簡稱爲gawk
    
gwak -pattern scanning and processing language


處理:一次讀取一行文本,根據指明的輸入分隔符切割爲n個組成部分;內
建變量$1...$n   顯示整行片段爲$0


基本用法:gawk  [options]  'program'  FILE1 [FILE...n]

    program:  PATTREN{ACTION STATEMENTs}

        語句之間用;分隔

選項 
 -F ""指明字段分隔符
 -v  var=value :自定義變量
 

1、print 
  

    print item1,item2,...
例如  awk '{print $1,$2}'  以默認空格爲分割字段顯示$1  $2
不寫,的話會連接顯示 $1$2
(1)都號分隔符
(2)輸出的item可以是字符串,數值,當前記錄的子段、變量或awk表達式
字符串連接時  '{print "hello:" $1}' 加入字符  ""裏面的東西不會改變,
因此$1不能在""裏面
(3)省略item,就相當於print $0  打印整行


2、變量
  1 內建變量
    FS:input  filed seperator,默認爲空白字符
    OFS:output filed seperator,默認爲空白字符
    RS: 輸入時的換行符
    ORS:輸出時的換行符    
    NF:顯示行的字段數
這個時候如果打印$NF 是打印每行字段的最後一個字段
因爲你統計了每行的字段
{print NF}  {print NR}
因此打印變量不要加$

    NR:統計文件的行數
    FNR:每個文件單獨計數行數  {print FNR}  file1 file2 ..
    FILENAME:當前正在處理的文件名  
如果直接打印,是每處理一行就會顯示一次文件名
可以用 'BEGIN{print FILENAME}' 顯示一次

    ARGC:命令行參數的個數
    ARGV:數組,保存的是命令行中所給定的各參數
例如  awk 'BEGIN{print ARGV[0] ARGV[1] ARGV[2] ARGC}' file1 file2
就會顯示  awk  file1  file2  3  三個參數和總計的參數量

例如
eg1: awk -v FS=':' '{print $1}'  /etc/passwd
     等於awk -F: '{print $1}'  /etc/passwd

eg2:定義輸出分隔符
  awk -v FS=':' -v OFS=':'  '{print $1}'  /etc/passwd
輸出也打印爲分割符爲:

eg3  -v RS=' '  把空白字符全部當做換行符
    -v ORS='#'  #作爲輸出的換行

 2 自定義變量
    -v  var=value
    變量名區分大小寫、引用變量不需要$

如果不對文件做處理,必須'BEGIN{}'  而不是在處理文件過程中,就不用加文件名稱了

 3printf 命令

 格式化輸出:printf FORMAT, item1 ....

    (1)FORMAT必須給出
    (2)printf不會自動換行,需要顯式給出\n
    (3)FORMAT中需要分別爲後面的每個item指定一個格式化符號
    格式符
    %c 顯式字符的ASCII碼
    %d,%i 顯式爲十進制,整數
    %e,%E 顯式爲科學計數法
    %f 顯式爲浮點數
    %g,%G以科學計數法,浮點形式顯式數值
    %s顯式字符串
    %u 無符號整數
    %% 顯式% 本身

例如 awk -F: '{printf "Username: $s\n",$1}'  /etc/passwd
類似C語言版的輸出

awk -F: '{printf "Username: $s, UID:%d\n",$1,$3}'  /etc/passwd

    修飾符
    #[.#]: 第一個#控制顯示的寬度,第二個#控制小數的精度可以不加
        %3.1f

awk -F: '{printf "Username: $15s, UID:%8d\n",$1,$3}'  /etc/passwd

默認爲右對齊顯示   
    -爲左對齊
awk -F: '{printf "Username: $-15s, UID:%8d\n",$1,$3}'  /etc/passwd
        %-15s 左對齊
    -左對齊
    +顯示數值的符號


 4操作符

   算數操作符:
    x-+\*^%
    -x 負值
    +x 轉換爲數值

   字符串操作符:沒有符號的操作符,字符串連接

   賦值操作符
    =,+=,-=,*=,%=,^=,\=
    ++,--

   比較操作符
    < > >=  <= == != 

   模式匹配符
    
    ~  是否匹配   
    !~是否不匹配

   邏輯操作符
    && ||  
    !
   函數調用
    function_name(argu1,argu2, ...)

   條件表達式
    selector?if-true-expression:if-false-expression
    1?2:3
    1對執行2,不對執行3
    
   eg:  awk -F: '{$3>=1000?usertype="common":usertype="sys";printf
 "%15s:%-s\n",$1,usertype}'  /etc/passwd

 5 PATTERN

   (1) empty:空模式,匹配每一行
   (2)/regular expression/  :僅處理能被此處模式匹配到的行(過濾)
eg1:  awk '/^UUID/{print $1}'  /etc/fstab
僅顯示開頭爲UUID 的行
 awk '!/^UUID/{print $1}'  /etc/fstab
加!對整個過濾模式取反

正則表達式

   (3)relational expression:關係表達式:如果有“真”有“假”;結果爲真才被處理
    真:結果爲非0值,非空字符串
eg: awk -F: '$3>=1000{prinf $1,$3}' /etc/passwd

awk -F: '$NF=="/bin/bash"{print $1,$NF}'  /etc/passwd
打印最後一個字段爲/bin/bash的行

   (4)line ranges:行範圍,
    startline,endline (地址定界) /pat1/ /pat2/
    
    注意:不支持直接給出數字的格式
    awk -F: '(NR>=2&&NR<=10){print $1}'  /etc/passwd
   (5)BEGIN/END模式
    BEGIN{} 在開始處理文件中的文本之前執行一次
    END{}在文本處理完成之後執行一次
    

6常用的action

 (1)表達式Expressions
 (2)控制語句
 (3)組合語句
 (4)輸入語句
 (5)輸出語句

7控制語句
  
  if(confition) {statements}
  if(confition) {statements} else {statements}
    ...
    ...

 7.1  if-else
   語法: if(conditon) statement [else statement]


   awk -F: '{if($3>=1000) print $1,$3}'  /etc/passwd

   awk -F: '{if($3>=1000) {print $1,$3} else {print $1,$3}}'  /etc/passwd


   df -h|awk -F[%]  '{print $5}' |awk '{print $NF}'
   顯示最後一個字段

    
   df -h|awk -F[%]  '/^\/dev/{print $5}' |awk '{print $NF}'
   \/轉義    以/dev開頭的行

   7.2while循環
      語法:while(conditon)  statement
    條件“真”,進入循環;條件“假”,退出循環


    使用場景:對一行內的多個字段逐一類似處理時使用;對數組元素逐一處理

    awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i);i++}}'  /etc/grub2.cfg
         統計字段

    
    awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7){print $i,length($i)};i++}}'  /etc/grub2.cfg
         統計字段
    

  7.3 do-while循環
    do statement  while(condition)
    至少執行一次循環體

  7.4for循環
      語法:for(expr1;expr2;expr3) statement


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

    
  7.5 switch語句
     語法:switch(expression)

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

  7.6 break  continue
    break [n]
    continue
  7.7next
    提前結束對本行的處理而直接進入下一行

  awk -F: '{if($3%2!=0) next; print $1,$3}'  /etc/passwd


 8array
    關聯數組array[index-expression]

    index-expression
    (1)可使用任意字符串
    (2)如果某數組元素事先不存在,在引用時awk會自動創建此元素,並且初始化爲
“空串”
    

    要判斷數組中是否存在某元素,要使用“index in array”格式進行

    weekdays["mon"]="Monday"  引用元素不要加$
    要使用雙引號

eg:  awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]=Tuesday;print weekdays["mon"]}'

    遍歷數組中每個元素
    for(var in array) {for-body}

    var會遍歷array的每個索引

netstat -tan |awk '/^tcp\>/{state[$NF]++}END{for(i in state) {print i,state[i]}}'

其中  state[$NF]++表示 索引數組的自增
結果爲  
Listen  3
Establish  3
用於統計服務很給力

awk '{ip[$1]++}END{for (i in ip) {print i,ip[i]}}'  /var/log/httpd/access_log
這就是所謂的報告生成器


例題:
1統計/etc/fstab中每個文件系統類型出現的次數
awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}'  /etc/fstab

    
2統計指定文件中每個單詞出現的次數

行內字段遍歷

awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for (i in count) {print i,count[i]}}'  /etc/fstab

9函數
  9.1內置函數
    數值處理
    rand()  返回0-1之間一個隨機數

    字符串處理
    length([s])  返回指定字符串的長度
    sub(r,s,[t])  r表示模式來查找t所表示的字符串中的匹配的內容,並將其第一次出現替換爲s
    gsub(r,s,[t])  全局替換
    
    split(s,a,[r]) 以r爲分隔符切割字符s,並將切割後的結果保存至a所表示的數組中。數組從1標號
例如  netstat -tan |awk '/^tcp\>/{split($5,ip,":");print ip[1]}'   打印每一行的ip    


netstat -tan |
awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'
統計ip次數

  9.2自定義函數


 

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