Shell腳本之awk篇

目錄: linux

1、概述
2、awk基本語法格式
3、awk基本操做
4、awk條件及循環語句
5、awk函數
6、awk演示示例(源自於man手冊)

1、概述
1. 產品概述:
    awk是一種編程語言,用於在linux/unix下對文本和數據進行掃描與處理。數據能夠來自標準輸入、文件、管道。
    awk分別表明其做者姓氏的第一個字母。由於它的做者是三我的,分別是Alfred Aho、Peter Weinberger、Brian Kernighan。
    實際上awk有不少種版本,如:awk、nawk、mawk、gawk、MKS awk、tawk...  這其中有開源產品也有商業產品。
    目前在Linux中經常使用的awk編譯器版本有mawk,gawk,其中以RedHat爲表明使用的是gawk,以Ubuntu爲表明使用的是mawk。
    gawk是GNU Project 的awk解釋器的開源代碼實現。
    本文將以gawk做爲講解工具。
2. 原理:
    1). awk逐行掃描文件,從第一行到最後一行,尋找匹配特定模式的行,並在這些行上進行你想要的操做。
    2). awk基本結構包括模式匹配(用於找到要處理的行)和處理過程(即處理動做)。
       pattern  {action} 正則表達式

  # 提示:awk讀取文件內容的每一行時,將對比改行是否與給定的模式相匹配,若是匹配則執行處理過程,不然對該行不作任何處理。
若是沒有指定處理腳本,則把匹配的行顯示到標準輸出,即默認處理動做是print打印行;
若是沒有指定模式匹配,則默認匹配全部數據。

      3). awk有兩個特殊的模式:BEGIN和END,他們被放置在沒有讀取任何數據以前以及在全部數據讀取完成之後執行。
3. awk流程圖: 編程

awk流程

  提示:awk將文件中的每一行看成一條記錄,並將記錄分割爲若干字段,默認以空格或製表符爲分隔符。

如This   is   a    test    file.    將分割爲5個字段,awk能夠對這5個字段進行分別處理。

2、awk基本語法格式
1. 格式:
gawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
註釋:POSIX or GNU style options表示gawk支持POSIX以及GNU兩種選項;-f後接腳本文件;file表示準備處理的文檔名稱。
2. gawk支持如下選項:
     -F fs
         --field-separator fs
     指定以fs做爲輸入行的分隔符(默認分隔符爲空格或製表符)
     -v var=val
         --assign var=val
     在執行處理過程之前,設置一個變量var值爲val
     -f program-file
     --file program-file
    從腳本文件中讀取AWK指令,以取代在命令參數中輸入處理腳本
    -W compat
    -W traditional
    --compat
    --traditional
    使用兼容模式運行awk,GNU擴展選項將被忽略
    -W copyleft
        -W copyright
        --copyleft
        --copyright
    輸出簡短的GNU版權信息
    -W dump-variables[=file]
        --dump-variables[=file]
    打印全局變量(變量名、類型、值)到文件中,若是沒有提供文件名,則自動輸出至名爲dump-variables的文件中。
    示例:[jacob@localhost ~]# awk  -W  dump-variables=out.txt  'x=1  {print x}'  test.txt
    -W exec file
    --exec file
    相似於-f選項,但腳本文件須要以#!開頭;另外命令行的變量將再也不生效
    -W help
        -W usage
        --help
        --usage
    顯示各個選項的簡短描述
3. awk程序結構
    一個awk程序包含一系列的  模式 {動做指令} 或是函數定義。
    模式能夠是:
    BEGIN
    END
    表達式
    表達式,表達式
    動做指令須要以{}引發來
4. 簡單示例:
    [jacob@localhost ~]# awk  '/^$/  {print  "Blank line}'   test.txt
    備註:/^$/經過正則表達式匹配空白行,動做爲打印Blank line;即test.txt若有N個空白行,awk將在屏幕打印N個Blank line。
    [jacob@localhost ~]# awk  '/HOSTNAME/'  /etc/sysconfig/network
    備註:打印包含主機名的行,由於沒有指定動做指令,默認動做爲打印。
    [jacob@localhost ~]# cat  awk.sh
    '/^$/  {print  "Blank line}'
    [jacob@localhost ~]# awk  -f  awk.sh  test.txt
    備註:提早編輯一個awk腳本再經過-f選項調用該腳本。

3、awk基本操做
1. 記錄與字段
    awk一次從文件中讀取一條記錄,並將記錄存儲在字段變量$0中。記錄被分割爲字段並存儲在$1,$2 ..., $NF中(默認使用空格或製表符爲分隔符)。
    內建變量NF爲記錄的字段個數
    示例:
    [jacob@localhost ~]# echo  hello the world |
    >awk  '{print  $1,$2,$3}'

    備註:讀取輸入行並輸出第一個字段,第二個字段,第三個字段。
    [jacob@localhost ~]# echo  hello the world |
    >awk  '{print  $0}'

    備註:讀取輸入行並輸出該行。
    [jacob@localhost ~]# echo  hello the world |
    >awk  '{print  NF}'

    備註:讀取輸入行並輸出該行的字段個數:3個字段。
    [jacob@localhost ~]# echo  hello the world |
    >awk  '{print  $NF}'

    備註:讀取輸入行並輸出該行的第三個字段,由於NF爲3,因此$NF等同於取行的最後一個字段。
2. 字段分隔符
    默認awk讀取數據以空格或製表符做爲分隔符,但能夠經過-F或FS(field separator)變量來改變分隔符。
    示例:
    [jacob@localhost ~]# awk  -F:  '{print $1}'  /etc/passwd
    [jacob@localhost ~]# awk  'BEGIN {FS = ":"} {print $1}'  /etc/passwd

    備註:以上兩個示例均將字段的分隔符改冒號(:),即以冒號爲分隔符打印passwd文件的第一個字段(賬號名稱)。
    注意:若是使用FS改變分隔符的話,須要在BEGIN處定義FS,由於在讀取第一行前就須要改變字段分隔符。
    進階:指定多個字段分隔符(文檔內容爲:hello the:word,!)

     [jacob@localhost ~]# echo  'hello the:word,!' |
     >awk  'BEGIN {FS="[:, ]"}  {print $1,$2,$3,$4}'

3. 內置變量
    如下爲awk內置變量:
          ARGC        命令行參數個數
          FILENAME    當前輸入文檔的名稱
          FNR        當前輸入文檔的當前記錄編號,尤爲當有多個輸入文檔時有用
          NR        輸入流的當前記錄編號
          NF        當前記錄的字段個數
          FS        字段分隔符
          OFS        輸出字段分隔符,默認爲空格
          ORS        輸出記錄分隔符,默認爲換行符\n
          RS        輸入記錄分隔符,默認爲換行符\n
    示例:
    [jacob@localhost ~]# cat  test1.txt tomcat

 
  1. This is a test file. 
  2. Welcome to Jacob's Class. 

    [jacob@localhost ~]#cat   test2.txt app

 
  1. Hello the world. 
  2. Wow! I'm overwhelmed. 
  3. Ask for more. 

    [jacob@localhost ~]# awk  '{print FNR}'  test1.txt  test2.txt 編程語言

 

    備註:輸出當前文檔的當前行編號,第一個文件兩行,第二個文件三行。
    [jacob@localhost ~]# awk  '{print NR}'  test1.txt  test2.txt 函數

 

    備註:awk將兩個文檔做爲一個總體的輸入流,經過NR輸入當前行編號。
    [jacob@localhost ~]# awk  '{print NF}'  test1.txt 工具

 

    備註:test1.txt文檔的第一行有5個字段,第二行有4個字段。
    [jacob@localhost ~]# awk  'BEGIN {FS = ":"} {print $1}'  /etc/passwd
    [jacob@localhost ~]# awk  '{print $1,$2,$3}'  test1.txt

    備註:默認print輸出時,各參數將的輸出分隔符默認爲空格,因此輸出內容以下
    This is a
    Welcome to Jacob's
    [jacob@localhost ~]# awk  'BEGIN {OFS="-"} {print $1,$2,$3}'  test1.txt spa

  備註:經過OFS將輸出分隔符設置爲"-",這個print在輸出第1、2、三個字段時,中間的分隔符爲"-",結果以下
 
  1. This-is-a 
  2. Welcome-to-Jacob's 

    [jacob@localhost ~]# cat  test3.txt .net

 
  1. mail from: tomcat@gmail.com 
  2. subject:hello 
  3. data:2012-07-12 17:00 
  4. content:Hello, The world. 
  5.  
  6. mail from: jerry@gmail.com 
  7. subject:congregation 
  8. data:2012-07-12 08:31 
  9. content:Congregation to you. 
  10.  
  11. mail from: jacob@gmail.com 
  12. subject:Test 
  13. data:2012-07-12 10:20 
  14. content:This is a test mail. 

    [jacob@localhost ~]# awk 'BEGIN {FS="\n"; RS=""} {print $3}'  test3.txt
    備註:讀取輸入數據,以空白行爲記錄分隔符,即第一個空白行前的內容爲第一個記錄,第一個記錄中字段分隔符爲換行符。
    以上awk的效果爲打印全部的郵件時間,即每一個記錄的第三個字段。
4. 表達式與操做符
    表達式是由變量、常量、函數、正則表達式、操做符組成,awk中變量有字符變量和數字變量。若是在awk中定義的變量沒有初始化,則初始值爲空字串或0。
    注意:字符操做時必定記得須要加引號
    1) 變量定義示例:
        a="welcome to beijing"
        b=12
    2) 操做符(awk操做符與C語言相似)
    +        加
    -        減
    *        乘
    /        除
    %        取餘
    ^        冪運算
    ++        自加1
    --        自減1
    +=        相加後賦值給變量(x+=9等同於x=x+9)
    -=        相減後賦值給變量(x-=9等同於x=x-9)
    *=        相乘後賦值給變量(x*=9等同於x=x*9)
    /=        相除後賦值給變量(x/=9等同於x=x/9)
    >        大於
    <        小於
    >=        大於等於
    <=        小於等於
    ==        等於
    !=        不等於
    ~        匹配
    !~        不匹配
    &&        與
    ||        或
    操做符簡單示例:
    [jacob@localhost ~]# echo "test"  | awk  'x=2  {print x+3}'
    [jacob@localhost ~]# echo "test"  | awk  'x=2,y=3 {print x*2, y*3}'
    [jacob@localhost ~]# awk  '/^$/ {print x+=1}'   test.txt
                    備註:統計全部空白行
    [jacob@localhost ~]# awk  '/^$/ {x+=1}  END {print x}'   test.txt        備註:打印總空白行個數
    [jacob@localhost ~]# awk -F:  '$1~/root/   {print  $3}'   /etc/passwd     備註:打印root的ID號
    [jacob@localhost ~]# awk -F:  '$3>500  {print  $1}'      /etc/passwd     備註:列出計算機中ID號大於500的用戶名

4、awk條件及循環語句
    1. IF條件判斷格式:
    if (表達式)
        動做1
    else
        動做2
    或者if (表達式)  動做1;else 動做2
    說明:若是表達式的判斷結果爲真則執行動做1,不然執行動做2。
    示例:(判斷boot分區可用容量小於20M時報警,不然顯示OK)
    [jacob@localhost ~]# df  |grep    "boot"  |awk  '{if($4<20000) print "Alart"; else print "OK"}'
    2. 循環
    while (條件)
        動做
    x=1
    while (i < 10) {
        print $i
    }
    示例:
    [jacob@localhost ~]# awk  'i=1 {}  BEGIN { while (i<=10) {++i; print i}}'  test.txt

    do
        動做
    while (條件)
    示例:
    [jacob@localhost ~]# awk  'BEGIN { do {++x;print x} while (x<=10)}'  test.txt
    for (變量;條件;計數器)
        動做
    示例:
    for (i=1;i<=10;i++)
        print i
    [jacob@localhost ~]# awk  'BEGIN {for(i=1;i<=10;i++) print i}'  test.txt
    [jacob@localhost ~]# awk  'BEGIN {for(i=10;i>=1;i--)  print i}'   test.txt

    說明:由於以上循環語句使用的awk均使用的BEGIN模式,因此輸入文檔能夠爲任意文檔(可有可無)。
    3. Break與Continue
    break        跳出循環
    continue    終止當前循環
    示例:
    for  (i=1; i<=10;i++) {
        if (i=5)
            continue
        print i
    }

    說明:打印1-4,6-10
    for  (i=1; i<=10;i++) {
        if (i=5)
            break
        print i
    }

    說明:僅打印1-4

5、函數
    1. rand ()        產生0-1之間的浮動類型的隨機數
    備註:rand產生隨機數時須要經過srand()設置一個參數,不然單獨的rand()每次刪除的隨機數都是同樣的。
    示例:
    [jacob@localhost ~]# awk  'BEGIN  {print  rand(); srand(); print srand()}'  test.txt
    2. gsub(x,y,z)        在字串z中使用字串y替換與正則表達式x相匹配的全部字串,z默認爲$0
        sub(x,y,z)        在字串z中使用字串y替換與正則表達式x相匹配的第一個字串,z默認爲$0
    示例:
    [jacob@localhost ~]# awk -F:   'gsub(/root/,"jacob",$0) {print $0}' /etc/passwd    備註:將passwd每行中全部的root修改成jacob顯示至屏幕
    [jacob@localhost ~]# awk -F:   'sub(/root/,"jacob",$0) {print $0}' /etc/passwd    備註:將passwd每行中第一個root修改成jacob顯示至屏幕
    sub至關於sed中的s///,gsub至關於sed中的s///g。
    3. length(z)        返回字串z的長度
    示例:
    [jacob@localhost ~]# awk  '{print length()}'  test.txt        備註:顯示test.txt文檔每行的字符長度
    4. gentline        從輸入中讀取下一行內容
    示例:
    [jacob@localhost ~]# df  -h

 
  1. Filesystem            Size  Used Avail Use% Mounted on 
  2. /dev/mapper/VolGroup00-LogVol00 
  3.                        19G  3.6G   15G  21% / 
  4. /dev/sda1              99M   14M   81M  15% /boot 
  5. tmpfs                 141M     0  141M   0% /dev/shm 
  6. none                  140M  104K  140M   1% /var/lib/xenstored 
  說明:從以上命令的輸出結果能夠看出,分區的剩餘容量顯示在第4列,但惟獨/根分區的記錄顯示在了兩行;咱們須要判斷當記錄的字段個數爲1時,讀取下一行,並將該行的第3列顯示至屏幕。

[jacob@localhost ~]# df  -h |awk  '{if(NF==1) {getline; print $3}; if(NF==6) print $4}'
[jacob@localhost ~]# df  -h |awk  'BEGIN {print "Disk Free:"} {if(NF==1) {getline; print $3}; if(NF==6) print $4}'


6、awk演示示例(源自於man手冊)
       1. emulate cat.            模擬cat程序    

        { print }

       2. emulate wc.            模擬wc程序,統計行數、單詞數、字符數

        { chars += length($0) + 1  # add one for the \n
          words += NF
        }

        END{ print NR, words, chars }


       3. sum the second field of every record based on the first field.        根據第一列的內容統計第二列的數據

        $1 ~ /credit|gain/ { sum += $2 }
        $1 ~ /debit|loss/  { sum -= $2 }

        END { print sum }


       4. Print and sort the login names of all users:                顯示計算機賬號用戶名並排序

        BEGIN     { FS = ":" }         { print $1 | "sort" }

相關文章
相關標籤/搜索