天天看點

awk指令介紹和常見使用方法

awk、sed、grep這三個指令并稱為文本處理三劍客,但是awk的功能遠遠多出其他兩個指令很多。最初由貝爾實驗室研制。後來GUN組織在awk的基礎上研制了gawk,現在我們在Linux使用的一般都是gawk這個指令,但是為了一些習慣,将awk作為gawk的連結,也就是說,現在在bash中使用awk還是使用gawk都是一樣的。接下來為了友善,直接稱之為awk。

那麼awk到底好在哪裡呢?它的好處是在于使用這個指令可以進行簡單的程式設計,在使用别的指令的時候需要寫一個腳本才能實作的功能,使用這個指令就可以直接實作。下面簡單的介紹這個指令的格式:

    awk [options] 'program' file...

program部分可以是: pattern{action statement;...}

 pattern部分可以是:BEGIN,END,用來決定動作語句何時觸發及通過什麼事件觸發,比如如果這裡是“BEGIN”那麼就是在這個指令執行之前執行,同理,“END”是在這個指令執行完畢後執行。“BEGIN”和“END0”都是可以選擇的,沒有也可以;

 action statement 部分可以是:print,printf,它們是對資料進行處理的語句,通常放在一對{}之中,決定着在執行這個指令之後産生的資料如何的表達。

  在使用awk對資料進行處理時,會根據特定的辨別對資料進行分段,這種特定辨別就是分隔符,預設是空白字元,可以通過“-F”來進行指定。經過分隔符分隔之後的每一個小分段,都稱為一個分段(Field);預設awk會使用内置位置變量來存儲各個字段的值;這些變量就是$1,$2,$3,...$N;由換行符分隔的資料中的每一行,就是一個記錄;在awk處理資料的時候,使用$0儲存整行的内容。

    常用選項

-F:用來指明此次資料處理的字段分隔符,預設是空白分隔符

-v:var=value:用于自定義變量和為自定義變量賦初始值

對于變量,我們可以自己定義,也可以使用指令自己的變量,指令自己的變量有很多,比如:

    FS:input field seperator,輸入字段分隔符,預設空白字元

示例:

<code>~]</code><code># awk -v FS=':' '{print $1}' /etc/passwd</code>

OFS:outpit field seperator,輸入字段分隔符,預設空白字元

<code>~]</code><code># awk -v FS=':' -v OFS=':' '{print $1 $3}' /etc/passwd</code>

RS:input record seperator,輸入記錄分隔符,預設換行符;

注意:即使指定了新的輸入記錄分隔符,原換行符仍然有效

<code>~]</code><code># awk -v RS='/' '{print $0}' /etc/passwd</code>

ORS:output record seperator,輸出記錄分隔符

NF:number of field,字段數量

(不加$輸出這個變量的值,加上$輸出最後一個字段)

<code>~]</code><code># awk -v FS=':' '{print NF}' /etc/passwd</code>

<code>~]</code><code># awk -v FS=':' '{print $NF}' /etc/passwd</code>

<code>~]</code><code># awk -v FS=':' '{print $(NF-1)}' /etc/passwd</code>

NR:number of record,行數;鑒于awk周遊檔案每行的特性,可以将該變量了解為行号

<code>~]</code><code># awk '{print NR}' /etc/passwd    #(如果同時輸出多個檔案,那麼行數會累加)</code>

FNR:file number of record,分别統計各個檔案的行數,行号

<code>~]</code><code># awk '{print FNR}' /etc/passwd</code>

FILENAME:輸出目前正在處理的檔案的檔案名;

<code>~]</code><code># awk '{print FILENAME}' /etc/passwd</code>

ARGC:argument count,整個指令行中的參數的數量,包括指令本身算一個

<code>~]</code><code># awk '{print ARGC}' /etc/passwd #(輸出結果為2,awk '{print ARGC}'是1,/etc/passwd是2)</code>

ARGV:數組,argument value,儲存了指令行中各個參數的具體内容

<code>~]</code><code># awk '{print ARGV[1]}' /etc/passwd #(輸出結果為awk)</code>

   還可以自己定義變量,定義的方法如下:

-v var=value

     注意:變量名區分字元大小寫

<code>~]</code><code># awk -v var1='hello' -F: '{print var1 ,$1}' /etc/passwd</code>

  除了變量,還可以定義數組:array[index_expression]

index_expression:

 1) 可以使用任意的字元串,字元串必須使用雙引号;

 2) 如果某數組元素事先不存在,當引用該元素時,awk會自動建立此元素,并且為該元素賦"空字元串"作為其初始值;

注意:如果想要判斷數組中某個元素是否存在,一般會使用"index in array"格式進行;

<code>~]</code><code># awk 'BEGIN{name["leader"]="zhang";name["mem1"]="li";name["mem2"]="wang";print name["leader"]}'</code>

  在這個指令中,變量是一個很重要也很有意義的東西,配合變量使用的就是如何将其輸出,在上面的例子中,使用到了print,這個選項是将一些内容進行輸出,可以是一些變量,或者是一些自己想要輸出的字元串,比如:

<code>awk</code> <code>'{print "aaaaaaaaaa" $1}'</code> <code>/etc/fstab</code>

  上面這條指令就是取出“/etc/fstab”中的每一行的第一列進行輸出,并且在輸出的時候前面加上一串a,使用這種方法我們可以對輸出内容進行控制。但是這種方法輸出的格式可能并不美觀。是以就用到了另外一種指令,叫做“printf”選項,這個選項可以對輸出的格式進行控制,效果如同C語言中的那個“printf”。

    printf選項:

格式化輸出指令:printf "FORMAT" item1,item2,...

要點:

      1)必須給出合适的FORMAT(顯示的格式)

2)預設不自動換行,需要顯式給出換行控制符(\n)

3)FORMAT中需要為後面的每一個item指定一個格式符

格式符可以有以下幾種,選擇了一種,就會将後邊對應的“item”語句按照這種格式進行輸出:

%c:顯示字元的ASCII碼

%d,%i:顯示十進制整數

%f:顯示浮點數字

%e,%E:使用科學計數法顯示數字

%g,%G:使用科學計數法顯示浮點數字

%s:顯示字元串

%u:(unsigned)顯示無符号整數

%%:顯示%自身

修飾符:

#[.#]:第一個數字用來控制顯示寬度;第二個數字表示小數點的精度(第二個數可以省略)

例如:%3.1f %5s

-:表示采用左對齊機制;預設是右對齊; %-15s

+:顯示數字的正負符号; %+d

<code>awk</code> <code>-F: </code><code>'{printf "%20s: %-5s\n",$1,$3}'</code> <code>/etc/passwd</code>

  在進行輸出的時候還可以進行運算,可以使用一些運算符來到這個目的:

算數操作符:

     x+y,x-y,x*y,x/y,x^y,x%y

-x:将正數轉換為負數

+x:将字元串轉換為數值

       示例:

<code>awk</code> <code>'BEGIN{print 1+2}'</code>

字元串操作符:

沒有符号的操作符,表示字元串連接配接之意

指派操作符:

=,+=,-=,*=,/=,%=,^=

++,--

比較操作符:

&gt;,&gt;=,&lt;,&lt;=,==,!=

        示例:

<code>awk</code> <code>-F: </code><code>'$3==1000{print $0}'</code> <code>/etc/passwd</code>

模式比對操作符

~:左側的字元串是否能夠被右側的模式所比對

!~:左側的字元串是否不能夠被右側的模式所比對

  示例:

<code>awk</code> <code>-F: </code><code>'$NF~/bash/{print $0}'</code> <code>/etc/passwd</code>

邏輯操作符:

&amp;&amp;:與

||:或

<code>awk</code> <code>-F: </code><code>'$3&lt;=1000&amp;&amp;$3&gt;=500{print $0}'</code> <code>/etc/passwd</code> <code>#顯示UID在使用者500-1000之間的</code>

條件表達式:

condition(selector)?if-true-expression:if-false-expression

        (首先寫判斷條件,然後使用一個“?”進行分隔,後邊緊跟的是如果前邊的判斷條件成立所執行的指令,再然後使用“:”進行分隔,後跟如果判斷條件不符合所執行的指令)

<code>awk</code> <code>-F: </code><code>'{$3&gt;=1000?usertype="a":usertype="b";printf "%-20s: %-20s\n",usertype,$1}'</code> <code>/etc/passwd</code>

<code>awk</code> <code>-F: </code><code>'{$3&gt;=1000?usertype="a":usertype="b";print usertype,$1}'</code> <code>/etc/passwd</code>

  這個指令的強大之處還在于它可以達到grep和sed的效果,比如使用比對模式就可以實作grep的效果:

  在上面的指令格式中可以看到有PATTERN這麼一個選項,它可以是以下五種:

1)empty:空模式,處理檔案中的每一行

2)[!]/REGEXP/:僅處理[不]能被PATTERN比對到的行

<code>~]</code><code># awk '[!]/^r/{print}' /etc/passwd</code>

3)關系表達式:$3&gt;=1000或者$NF~/bash/

4)行的範圍

/regexp1/,/regexp2/:從被regexp1比對的這一行開始到被regexp2比對的這一行結束,有多少這一類比對結果,就顯示多少次

<code>~]</code><code># awk '/^r/,/^a/{print}' /etc/passwd #這個指令的功能是比對所有從以r開頭的行到以a開頭的行</code>

5)BEGIN/END模式:

BEGIN{}:僅在開始處理檔案中的第一行文本之前執行一次的語句塊

<code>~]</code><code># awk -F: 'BEGIN{printf "%20s %5s\n","Username","UserID"}{printf "%20s %5s\n",$1,$3}' /etc/passwd</code>

注意:在輸出特定格式的表頭時,常用此語句塊;

END{}:僅在文本處理完成但指令尚未退出時執行一次的語句塊

<code>~]</code><code># awk -F: 'BEGIN{printf "%20s %5s\n","Username","UserID"}{printf "%20s %5s\n",$1,$3}END{print "========================\n",NR " users"}' /etc/passwd</code>

   除了能夠進行比對之外,還可以實作其他語言中的控制語句,比如:

1) if-else:

文法:if (condition) {statement} [ else {statement} ]

使用場景:對awk取得的整行或某個字段做條件判斷;

<code>~]</code><code># awk -F: '{if($3&gt;=1000) {print $1} else {print $1,$3}}' /etc/passwd</code>

2) while循環:條件為真,進入循環;條件為假,退出循環;

文法:while (condition) statement

使用場景:對一行内的多個字段逐一做類似的處理;對數組中各個元素周遊及處理;

<code>~]</code><code># awk '/^[[:space:]]*linux16/{i=1;while(i&lt;=NF) {printf "%s: %d\n",$i,length($i);i++}}' /etc/grub2.cfg</code>

3) do...while循環:

文法:do statement while (condition)

意義:同while循環,但至少執行一次循環體中的語句;

4) for循環:

文法:for (expr1; expr2; expr3) statement

expr1:變量賦初值;

expr2:條件判斷;

expr3:變量值的遞增或遞減調整;

<code>~]</code><code># awk '/^[[:space:]]*linux16/{for(i=1;i&lt;=NF;i++) {printf "%s: %d\n",$i,length($i)}}' /etc/grub2.cfg</code>

        或者配合數組來檢視已連接配接狀态下,同一用戶端的連接配接數量:

<code>~]</code><code># ss -tn | awk '/^ESTAB\&gt;/{print $NF}' | awk -F: '{state[$1]++}END{for(s in state){print state[s],s}}'</code>

    5) break 和 continue

break [n]:跳出循環,後頭跟上哪個數字就跳出幾層循環

continue:跳過本次循環,直接進入下次循環;

6) next語句:

提前結束對本行的處理,而直接進入下一行;

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

  在使用控制語句進行簡單程式設計的時候還可以使用函數,函數也分為指令内置函數和自建函數。内置函數常見的有以下兩個:

    length(string):計算字元串長度

split(string,array[,fieldsep])

<code>~]</code><code># awk '{print sdasdas $1 length($1)}' /etc/fstab</code>

<code>~]</code><code># awk '{split($0,user,":");print user[1]}' /etc/passwd</code>

<code></code>

本文轉自正經的青年51CTO部落格,原文連結: http://blog.51cto.com/11142243/1957568,如需轉載請自行聯系原作者