天天看點

linux 指令詳解 九

  <b>十一</b><b>.  awk程式設計:</b>

 <b>   1.  </b><b>變量:</b>

    在awk中變量無須定義即可使用,變量在指派時即已經完成了定義。變量的類型可以是數字、字元串。根據使用的不同,未初始化變量的值為0或空白字元串" ",這主要取決于變量應用的上下文。下面為變量的指派負号清單:

<b>符号</b>

<b>含義</b>

<b>等價形式</b>

=

a = 5

+=

a = a + 5

a += 5

-=

a = a - 5

a -= 5

*=

a = a * 5

a *= 5

/=

a = a / 5

a /= 5

%=

a = a % 5

a %= 5

^=

a = a ^ 5

a ^= 5

    /&gt; awk '$1 ~ /Tom/ {Wage = $2 * $3; print Wage}' filename

    該指令将從檔案中讀取,并查找第一個域字段比對Tom的記錄,再将其第二和第三個字段的乘積指派給自定義的Wage變量,最後通過print指令将該變量列印輸出。

    /&gt; awk ' {$5 = 1000 * $3 / $2; print}' filename

    在上面的指令中,如果$5不存在,awk将計算表達式1000 * $3 / $2的值,并将其指派給$5。如果第五個域存在,則用表達式覆寫$5原來的值。

    我們同樣也可以在指令行中定義自定義的變量,用法如下:

    /&gt; awk -F: -f awkscript month=4 year=2011 filename

    這裡的month和year都是自定義變量,且分别被指派為4和2000,在awk的腳本中這些變量将可以被直接使用,他們和腳本中定義的變量在使用上沒有任何差別。

    除此之外,awk還提供了一組内建變量(變量名全部大寫),見如下清單:

<b>變量名</b>

<b>變量内容</b>

ARGC

指令行參數的數量。

ARGIND

指令行正在處理的目前檔案的AGV的索引。

ARGV

指令行參數數組。

CONVFMT

轉換數字格式。

ENVIRON

從shell中傳遞來的包含目前環境變量的數組。

ERRNO

當使用close函數或者通過getline函數讀取的時候,發生的重新定向錯誤的描述資訊就儲存在這個變量中。

FIELDWIDTHS

在對記錄進行固定域寬的分割時,可以替代FS的分隔符的清單。

FILENAME

目前的輸入檔案名。

FNR

目前檔案的記錄号。

FS

輸入分隔符,預設是空格。

IGNORECASE

在正規表達式和字元串操作中關閉大小寫敏感。

NF

目前檔案域的數量。

NR

目前檔案記錄數。

OFMT

數字輸出格式。

OFS

輸出域分隔符。

ORS

輸出記錄分隔符。

RLENGTH

通過match函數比對的字元串的長度。

RS

輸入記錄分隔符。

RSTART

通過match函數比對的字元串的偏移量。

SUBSEP

下标分隔符。

    /&gt; cat employees2

    Tom Jones:4424:5/12/66:543354

    Mary Adams:5346:11/4/63:28765

    Sally Chang:1654:7/22/54:650000

    Mary Black:1683:9/23/44:336500

    /&gt; awk -F: '{IGNORECASE = 1}; $1 == "mary adams" { print NR, $1, $2, $NF}' employees2

    2 Mary Adams 5346 28765

    /&gt; awk -F: ' $1 == "mary adams" { print NR, $1, $2, $NF}' employees2

    沒有輸出結果。

    當IGNORECASE内置變量的值為非0時,表示在進行字元串操作和處理正規表達式時關閉大小寫敏感。這裡的"mary adams"将比對檔案中的"Mary Admams"記錄。最後print列印出第一、第二和最後一個域。需要說明的是NF表示目前記錄域的數量,是以$NF将表示最後一個域的值。

    awk在動作部分還提供了BEGIN塊和END塊。其中BEGIN動作塊在awk處理任何輸入檔案行之前執行。事實上,BEGIN塊可以在沒有任何輸入檔案的條件下測試。因為在BEGIN塊執行完畢以前awk将不讀取任何輸入檔案。BEGIN塊通常被用來改變内建變量的值,如OFS、RS或FS等。也可以用于初始化自定義變量值,或列印輸出标題。

    /&gt; awk 'BEGIN {FS = ":"; OFS = "\t"; ORS = "\n\n"} { print $1,$2,$3} filename

    上例中awk在處理檔案之前,已經将域分隔符(FS)設定為冒号,輸出檔案域分隔符(OFS)設定為制表符,輸出記錄分隔符(ORS)被設定為兩個換行符。BEGIN之後的動作子產品中如果有多個語句,他們之間用分号分隔。

    和BEGIN恰恰相反,END子產品中的動作是在整個檔案處理完畢之後被執行的。

    /&gt; awk 'END {print "The number of the records is " NR }' filename

    awk在處理輸入檔案之後,執行END子產品中的動作,上例中NR的值是讀入的最後一個記錄的記錄号。

    /&gt; awk '/Mary/{count++} END{print "Mary was found " count " times." }' employees2

    Mary was found 2 times.

    /&gt; cat testfile

    northwest       NW      Charles Main                3.0     .98     3       34

    western          WE      Sharon Gray                5.3     .97     5       23

    southwest       SW      Lewis Dalsass              2.7     .8      2       18

    southern         SO      Suan Chin                   5.1     .95     4       15

    southeast        SE      Patricia Hemenway        4.0     .7      4       17

    eastern           EA      TB Savage                   4.4     .84     5       20

    northeast        NE      AM Main Jr.                  5.1     .94     3       13

    north             NO       Margot Weber             4.5     .89     5       9

    central           CT       Ann Stephens              5.7     .94     5       13

    /&gt; awk '/^north/{count += 1; print count}' testfile     #如記錄以正則north開頭,則建立變量count同時增一,再輸出其值。

    1

    2

    3

    #這裡隻是輸出前三個字段,其中第七個域先被指派給變量x,在自減一,最後再同時列印出他們。

    /&gt; awk 'NR &lt;= 3 {x = $7--; print "x = " x ", $7 = " $7}' testfile

    x = 3, $7 = 2

    x = 5, $7 = 4

    x = 2, $7 = 1    

    #列印NR(記錄号)的值在2--5之間的記錄。

    /&gt; awk 'NR == 2,NR == 5 {print "The record number is " NR}' testfile

    The record number is 2

    The record number is 3

    The record number is 4

    The record number is 5

    #列印環境變量USER和HOME的值。環境變量的值由父程序shell傳遞給awk程式的。

    /&gt; awk 'BEGIN { print ENVIRON["USER"],ENVIRON["HOME"]}' 

    root /root

    #BEGIN塊兒中對OFS内置變量重新指派了,是以後面的輸出域分隔符改為了\t。

    /&gt; awk 'BEGIN { OFS = "\t"}; /^Sharon/{ print $1,$2,$7}' testfile

    western WE      5

    #從輸入檔案中找到以north開頭的記錄count就加一,最後在END塊中輸出該變量。

    /&gt; awk '/^north/{count++}; END{print count}' testfile

<b>    2.  重新定向:</b>

    在動作語句中使用shell通用的重定向輸出符号"&gt;"就可以完成awk的重定向操作,當使用&gt;的時候,原有檔案将被清空,同時檔案持續打開,直到檔案被明确的關閉或者awk程式終止。來自後面的列印語句的輸出會追加到前面内容的後面。符号"&gt;&gt;"用來打開一個檔案但是不清空原有檔案的内容,重定向的輸出隻是被追加到這個檔案的末尾。

    /&gt; awk '$4 &gt;= 70 {print $1,$2 &gt; "passing_file"}' filename  #注意這裡的檔案名需要用雙引号括起來。

    #通過兩次cat的結果可以看出&gt;和&gt;&gt;的差別。

    /&gt; awk '/north/{print $1,$3,$4 &gt; "districts" }' testfile

    /&gt; cat districts

    northwest Joel Craig

    northeast TJ Nichols

    north Val Shultz

    /&gt; awk '/south/{print $1,$3,$4 &gt;&gt; "districts" }' testfile

    southwest Chris Foster

    southern May Chin

    southeast Derek Jonhson

    awk中對于輸入重定向是通過getline函數來完成的。getline函數的作用是從标準輸入、管道或者目前正在處理的檔案之外的其他輸入檔案獲得輸入。他負責從輸入獲得下一行的内容,并給NF、NR和FNR等内建變量指派。如果得到一個記錄,getline就傳回1,如果達到檔案末尾就傳回0。如果出現錯誤,如打開檔案失敗,就傳回-1。

    /&gt; awk 'BEGIN { "date" | getline d; print d}'

    Tue Nov 15 15:31:42 CST 2011

    上例中的BEGIN動作子產品中,先執行shell指令date,并通過管道輸出給getline,然後再把輸出指派給自定義變量d并列印輸出它。

    /&gt; awk 'BEGIN { "date" | getline d; split(d,mon); print mon[2]}'

    Nov

    上例中date指令通過管道輸出給getline并指派給d變量,再通過内置函數split将d拆分為mon數組,最後print出mon數組的第二個元素。

    /&gt; awk 'BEGIN { while("ls" | getline) print}'

    employees

    employees2

    testfile

    指令ls的輸出傳遞給getline作為輸入,循環的每個反複,getline都從ls的結果中讀取一行輸入,并把他列印到螢幕。

    /&gt; awk 'BEGIN { printf "What is your name? "; \

        getline name &lt; "/dev/tty"}\

        $1 ~ name {print "Found" name " on line ", NR "."}\

        END {print "See ya, " name "."}' employees2

    What is your name? Mary

    Found Mary on line  2.

    See ya, Mary.    

    上例先是列印出BEGIN塊中的"What is your name? ",然後等待使用者從/dev/tty輸入,并将讀入的資料指派給name變量,之後再從輸入檔案中讀取記錄,并找到比對輸入變量的記錄并列印出來,最後在END塊中輸出結尾資訊。

    /&gt; awk 'BEGIN { while(getline &lt; "/etc/passwd" &gt; 0) lc++; print lc}'

    32

    awk将逐行讀取/etc/passwd檔案中的内容,在達到檔案末尾之前,計數器lc一直自增1,當到了末尾後列印lc的值。lc的值為/etc/passwd檔案的行數。

    由于awk中同時打開的管道隻有一個,那麼在打開下一個管道之前必須關閉它,管道符号右邊可以通過可以通過雙引号關閉管道。如果不關閉,它将始終保持打開狀态,直到awk退出。

    /&gt; awk {print $1,$2,$3 | "sort -4 +1 -2 +0 -1"} END {close("sort -4 +1 -2 +0 -1") } filename

    上例中END子產品中的close顯示關閉了sort的管道,需要注意的是close中關閉的指令必須和當初打開時的完全比對,否則END子產品産生的輸出會和以前的輸出一起被sort分類。<b>  3.  條件語句:</b>

    awk中的條件語句是從C語言中借鑒來的,見如下聲明方式:

    if (expression) {

        statement;

        ... ...

    }

    /&gt; awk '{if ($6 &gt; 50) print $1 "Too hign"}' filename

    /&gt; awk '{if ($6 &gt; 20 &amp;&amp; $6 &lt;= 50) { safe++; print "OK}}' filename

    } else {

        statement2;

    /&gt; awk '{if ($6 &gt; 50) print $1 " Too high"; else print "Range is OK" }' filename

    /&gt; awk '{if ($6 &gt; 50) { count++; print $3 } else { x = 5; print $5 }' filename

        statement1;

    } else if (expression1) {

        statement3;

    /&gt; awk '{if ($6 &gt; 50) print "$6 &gt; 50" else if ($6 &gt; 30) print "$6 &gt; 30" else print "other"}' filename

<b>   4.  循環語句:</b>

    awk中的循環語句同樣借鑒于C語言,支援while、do/while、for、break、continue,這些關鍵字的語義和C語言中的語義完全相同。

<b>    5.  流程控制語句:</b>

    next語句是從檔案中讀取下一行,然後從頭開始執行awk腳本。

    exit語句用于結束awk程式。它終止對記錄的處理。但是不會略過END子產品,如果exit()語句被指派0--255之間的參數,如exit(1),這個參數就被列印到指令行,以判斷退出成功還是失敗。

繼續閱讀