next up previous contents
Next: 實機練習題 Up: sed 與 awk 工具 Previous: sed 與 正規表示法   Contents

awk 工具

  1. awk 工具:相較於 sed 作用於一整個行的處理,awk 是『以行為一次處理的單位』, 而『以欄位為最小的處理單位』。
    [root@linux ~]# awk '條件類型1{動作1} 條件類型2{動作2} ...' filename
    
  2. 取出帳號與登入者的 IP:欄位的分隔符號為空白鍵或 [tab]
    [root@linux ~]# last
    csie   pts/0        192.168.1.12     Mon Aug 22 09:40   still logged in
    root     tty1                          Mon Aug 15 11:38 - 11:39  (00:01)
    reboot   system boot  2.6.11           Sun Aug 14 18:18         (7+15:41)
    csie   pts/0        192.168.1.12     Fri Aug 12 12:07 - 12:08  (00:01)
    
  3. 取出帳號與登入者的 IP,且帳號與 IP 之間以 [tab] 隔開:
    [root@linux ~]# last | awk '{print $1 "\t" $3}'
    csie  192.168.1.12
    root    Mon
    reboot  boot
    csie  192.168.1.12
    # 變數 $0 代表『一整列資料』,第一行的 $0 代表的就是『csie pts/0.... 』。
    
  4. awk 的內建變數
    1. 變數
      變數名稱 代表意義
      NF 每一行 ($0) 擁有的欄位總數
      $NF 每一行的最後一個欄位內容
      NR 目前 awk 所處理的是『第幾行』資料
      FS 目前的分隔字元,預設是空白鍵
    2. 承上例:列出每一行的帳號,並列出目前處理的行數及該行有多少欄位。
      [root@linux ~]# last | awk '{print $1 "\t lines: " NR "\t columes: " NF}'
      csie     lines: 1        columes: 10
      root     lines: 2        columes: 9
      reboot   lines: 3        columes: 9
      csie     lines: 4        columes: 10
      
  5. awk 的邏輯運算
    1. 邏輯運算字元
      運算單元 代表意義
      > 大於
      < 小於
      >= 大於或等於
      <= 小於或等於
      == 等於
      != 不等於
    2. /etc/passwd 以冒號 ":" 作為欄位的分隔,查閱第三欄小於 10 以下的數據,並且僅列出帳號與第三欄:
      [root@linux ~]# cat /etc/passwd | \
      > awk '{FS=":"} $3 < 10 {print $1 "\t " $3}'
      root:x:0:0:root:/root:/bin/bash
      bin      1
      daemon   2
      ......(以下省略)......
      # 因讀入第一行時,變數 $1, $2... 預設還是以空白鍵為分隔。因此,第一行沒有正確的顯示。
      
    3. 承上例,利用關鍵字 BEGIN 讓第一行正確顯示。
      [root@linux ~]# cat /etc/passwd | \
      > awk 'BEGIN {FS=":"} $3 < 10 {print $1 "\t " $3}'
      root     0
      bin      1
      daemon   2
      ......(以下省略)......
      
  6. 計算每個人薪資總額並且格式化輸出,薪資資料表 pay.txt 如下:
    Name    1st     2nd     3th
    csie   23000   24000   25000
    Wang  21000   20000   23000
    Lin   43000   42000   41000
       
    
    [root@linux ~]# cat pay.txt | \
    > awk 'NR==1{printf "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"Total" }
    NR>=2{total = $2 + $3 + $4
    printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total}'
          Name        1st        2nd        3th      Total
          csie      23000      24000      25000   72000.00
        Wang      21000      20000      23000   64000.00
         Lin      43000      42000      41000  126000.00
    
    # 在 {} 內的有多個指令時,可利用分號『;』,或 [Enter] 按鍵來隔開指令。
    # 與 bash shell 的變數不同,在 awk 當中,變數可以直接使用,不需加上 $ 符號。
    
  7. awk 的動作內 { } 支援 if (條件):
    [root@linux ~]# cat pay.txt | \
    > awk '{if(NR==1) printf "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"Total"}
    NR>=2{total = $2 + $3 + $4
    printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total}'
    
  8. 例題:將如下 printf.txt 檔案內容以 awk 指令輸出,格式如下 printf.txt 輸出格式,其中每個欄位長度為 9 個字元。
    ## printf.txt 內容
    Name Chinese English Math
    Dmdyw 80 60 92
    csie 75 55 80
    Ken 60 90 70
    ##printf.txt輸出格式
         Name   Chinese   English      Math     Total
       Dmdyw        80        60        92    232.00
         csie        75        55        80    210.00
          Ken        60        90        70    220.00
    
練習題
  1. 如何利用 awk 取出帳號與登入者的 IP,且帳號與 IP 之間以 [tab] 隔開?
    Sol. last | awk '{print $1 "\t" $3}'
  2. 如何利用 awk 取出帳號,並列出目前處理的行數及該行有多少欄位,且之間以預設的分隔字元隔開?
    Sol. last | awk '{print $1 FS NR FS NF}'
  3. /etc/passwd 以冒號 ":" 作為欄位的分隔,如何查閱第三欄小於等於 50 以下的數據,並且僅列出帳號與第三欄?
    Sol. cat /etc/passwd | awk 'BEGIN {FS=":"} $3 %*<== 50 {print $1 "\t " $3}'*)
  4. 如何輸出 /etc/man.config 至印表機?
    Sol. pr /etc/man.config


next up previous contents
Next: 實機練習題 Up: sed 與 awk 工具 Previous: sed 與 正規表示法   Contents
2017-06-14