Shell腳本之awk篇


目錄:
一、概述
二、awk基本語法格式
三、awk基本操作
四、awk條件及循環語句
五、awk函數
六、awk演示示例(源自於man手冊)

 

一、概述

 

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個字段進行分別處理。

二、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的文件中。
    示例:

 

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. 簡單示例:

   

 

awk '/^$/ {print "Blank line}' test.txt

    備注:/^$/通過正則表達式匹配空白行,動作為打印Blank line;即test.txt如有N個空白行,awk將在屏幕打印N個Blank line。

awk '/HOSTNAME/' /etc/sysconfig/network

    備注:打印包含主機名的行,因為沒有指定動作指令,默認動作為打印。

cat awk.sh
'/^$/ {print "Blank line}'
awk -f awk.sh test.txt

    備注:提前編輯一個awk腳本再通過-f選項調用該腳本。

三、awk基本操作

 

1. 記錄與字段


    awk一次從文件中讀取一條記錄,並將記錄存儲在字段變量$0中。記錄被分割為字段並存儲在$1,$2 ..., $NF中(默認使用空格或制表符為分隔符)。
    內建變量NF為記錄的字段個數
    示例:

 

echo hello the world | awk '{print $1,$2,$3}'

      備注:讀取輸入行並輸出第一個字段,第二個字段,第三個字段。

echo hello the world | awk '{print $0}'

    備注:讀取輸入行並輸出該行。

echo hello the world | awk '{print NF}'

    備注:讀取輸入行並輸出該行的字段個數:3個字段。 

echo hello the world | awk '{print $NF}'

    備注:讀取輸入行並輸出該行的第三個字段,因為NF為3,所以$NF等同於取行的最后一個字段。

2. 字段分隔符


    默認awk讀取數據以空格或制表符作為分隔符,但可以通過-F或FS(field separator)變量來改變分隔符。
    示例:

 

awk -F: '{print $1}' /etc/passwd
awk 'BEGIN {FS = ":"} {print $1}' /etc/passwd

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

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
    示例:

 

cat test1.txt
This is a test file. 
Welcome to Jacob's Class.
cat test2.txt
Hello the world. 
Wow! I'm overwhelmed. 
Ask for more. 
   輸出當前文檔的當前行編號,第一個文件兩行,第二個文件三行:
awk '{print FNR}' test1.txt test2.txt
1
2
1
2
3
   awk將兩個文檔作為一個整體的輸入流,通過NR輸入當前行編號:
awk '{print NR}' test1.txt test2.txt
1
2
3
4
5

    test1.txt文檔的第一行有5個字段,第二行有4個字段:

awk '{print NF}' test1.txt
5
4
  1.  
    awk ' BEGIN {FS = ":"} {print $1}' /etc/passwd
  2.  
    awk '{ print $1,$2,$3}' test1.txt

    備注:默認print輸出時,各參數將的輸出分隔符默認為空格,所以輸出內容如下。

This is a
Welcome to Jacob's
awk 'BEGIN {OFS="-"} {print $1,$2,$3}' test1.txt

    備注:通過OFS將輸出分隔符設置為"-",這個print在輸出第一、二、三個字段時,中間的分隔符為"-",結果如下:

 
        
This-is-a
Welcome-to-Jacob's
 
        
cat test3.txt
  mail from: tomcat@gmail.com 
  subject:hello 
  date:2012-07-12 17:00 
  content:Hello, The world.

  mail from: jerry@gmail.com 
  subject:congregation 
  date:2012-07-12 08:31 
  content:Congregation to you.  

  mail from: jacob@gmail.com 
  subject:Test 
  date:2012-07-12 10:20 
  content:This is a test mail.
awk 'BEGIN {FS="\n"; RS=""} {print $3}' test3.txt

      備注:讀取輸入數據,以空白行為記錄分隔符,即第一個空白行前的內容為第一個記錄,第一個記錄中字段分隔符為換行符。
    以上awk的效果為打印所有的郵件時間,即每個記錄的第三個字段。

4. 表達式與操作符


    表達式是由變量、常量、函數、正則表達式、操作符組成,awk中變量有字符變量和數字變量。如果在awk中定義的變量沒有初始化,則初始值為空字串或0。
    注意:字符操作時一定記得需要加引號
    1) 變量定義示例:

 

  1.  
    a= "welcome to beijing"
  2.  
    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)
    >        大於
    <        小於
    >=        大於等於
    <=        小於等於
    ==        等於
    !=        不等於
    ~        匹配
    !~        不匹配
    &&        與
    ||        或
    操作符簡單示例:

echo "test" | awk 'x=2 {print x+3}'
echo "test" | awk 'x=2,y=3 {print x*2, y*3}'

   統計所有空白行:

awk '/^$/ {print x+=1}' test.txt

   打印總空白行個數:

awk '/^$/ {x+=1} END {print x}' test.txt

   打印root的ID號:

awk -F: '$1~/root/ {print $3}' /etc/passwd

   列出計算機中ID號大於500的用戶名:

awk -F: '$3>500 {print $1}' /etc/passwd

 

四、awk條件及循環語句


   

1. IF條件判斷格式:


    if (表達式)
        動作1
    else
        動作2
    或者if (表達式)  動作1;else 動作2
    說明:如果表達式的判斷結果為真則執行動作1,否則執行動作2。
    示例:(判斷boot分區可用容量小於20M時報警,否則顯示OK)

 

df | grep "boot" | awk '{if($4<20000) print "Alart"; else print "OK"}'

   

2. 循環

 

    while (條件)
        動作
    x=1
    while (i < 10) {
        print $i
    }

    示例:

awk 'i=1 {} BEGIN { while (i<=10) {++i; print i}}' test.txt

    do
        動作
    while (條件)

    示例:

awk 'BEGIN { do {++x;print x} while (x<=10)}' test.txt

    for (變量;條件;計數器)
        動作
    示例:
    for (i=1;i<=10;i++)
        print i

awk 'BEGIN {for(i=1;i<=10;i++) print i}' test.txt
awk 'BEGIN {for(i=10;i>=1;i--) print i}' test.txt 

    說明:因為以上循環語句使用的awk均使用的BEGIN模式,所以輸入文檔可以為任意文檔(無關緊要)。

   

3. Break與Continue


    break        跳出循環
    continue    終止當前循環
    示例:

  1.  
    for (i=1; i<=10;i++) {
  2.  
    if (i=5)
  3.  
    continue
  4.  
    print i
  5.  
    }

    說明:打印1-4,6-10

  1.  
    for (i=1; i<=10;i++) {
  2.  
    if (i=5)
  3.  
    break
  4.  
    print i
  5.  
    }

    說明:僅打印1-4

五、函數


    1. rand ()        產生0-1之間的浮動類型的隨機數
    備注:rand產生隨機數時需要通過srand()設置一個參數,否則單獨的rand()每次刪除的隨機數都是一樣的。
    示例:

 

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
    示例:

 

   將passwd每行中所有的root修改為jacob顯示至屏幕

awk -F: 'gsub(/root/,"jacob",$0) {print $0}' /etc/passwd

   將passwd每行中第一個root修改為jacob顯示至屏幕

awk -F: 'sub(/root/,"jacob",$0) {print $0}' /etc/passwd

    sub相當於sed中的s///,gsub相當於sed中的s///g。
   

3. length(z)

        返回字串z的長度
    示例:顯示test.txt文檔每行的字符長度

 

awk '{print length()}' test.txt

   

4. gentline

        從輸入中讀取下一行內容
    示例:

 

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列顯示至屏幕。

 

df -h | awk '{if(NF==1) {getline; print $3}; if(NF==6) print $4}'
df -h | awk 'BEGIN {print "Disk Free:"} {if(NF==1) {getline; print $3}; if(NF==6) print $4}'

 

六、awk演示示例(源自於man手冊)


      

1. emulate cat:模擬cat程序

     { print }

 

      

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

 

  1.  
    { chars += length($0) + 1 # add one for the \n
  2.  
    words += NF
  3.  
    }
  4.  
    END{ print NR, words, chars }

      

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

 

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

      

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

 

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

 

 

參考鏈接:https://blog.51cto.com/manual/932958

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM