文本處理三劍客之awk(原創)

文本處理三劍客之awk(原創)

AWK是一種優良的文本處理工具,LinuxUnix環境中現有的功能最強大的數據處理引擎之一。這種編程及數據操作語言(其名稱得自於它的創始人阿爾佛雷德·艾侯(Alfred Aho)、彼得·溫伯格(Peter Jay Weinberger)和布萊恩·柯林漢(Brian Wilson Kernighan)姓氏的首個字母)的最大功能取決於一個人所擁有的知識。AWK提供了極其強大的功能:可以進行正則表達式的匹配,樣式裝入、流控制、數學運算符、進程控制語句甚至於內置的變量和函數。它具備了一個完整的語言所應具有的幾乎所有精美特性。實際上AWK的確擁有自己的語言:AWK程序設計語言,三位創建者已將它正式定義爲“樣式掃描和處理語言”。它允許您創建簡短的程序,這些程序讀取輸入文件、爲數據排序、處理數據、對輸入執行計算以及生成報表,還有無數其他的功能。gawkAWKGNU版本。最簡單地說,AWK是一種用於處理文本的編程語言工具。AWK在很多方面類似於Unix shell編程語言,儘管AWK具有完全屬於其本身的語法。它的設計思想來源於SNOBOL4sedMarc Rochkind設計的有效性語言、語言工具yacclex,當然還從C語言中獲取了一些優秀的思想。在最初創造AWK時,其目的是用於文本處理,並且這種語言的基礎是,只要在輸入數據中有模式匹配,就執行一系列指令。該實用工具掃描文件中的每一行,查找與命令行中所給定內容相匹配的模式。如果發現匹配內容,則進行下一個編程步驟。如果找不到匹配內容,則繼續處理下一行。

在我們的Linux中,awk其實是gawk的一個軟連接,所以我們所使用的都是GNU AWK

awk的運行方式:

         (1) awk命令行

                   # awk

         (2) awk程序文件

                   # awk -f /path/from/awk_script

         (3) awk腳本

                   #!/bin/awk –f

Awk在處理文本時會將每一行讀取到自己的內存空間當中,並將每一行文本根據我們制定的分隔符等分成不同的區域,類似腳本的內置位置變量。在處理完之後,輸出時awk依然是按照一行來輸出的,即便是輸出的內容不是原來的一整行,輸出的分割符默認爲空格,也可以自定義。

基本用法:

         gawk [OPTIONS] 'program' FILE1 FILE2 ...

                   program: PATTERN{ACTION STATEMENT}

                            由語句組成,各語句間使用分號分隔;

                            ACTION: print, printf

         選項:

                   -F[]: 指明輸入字段分隔符,可以是多個,例:-F [:,]即用:當分隔符又用,當分隔符;

                   -v VAR_NAME=VALUE: 變量賦值;

                   -f /PATH/FROM/AWK_SCRIPT

1awk的輸出命令之一:print

                   用法:print item1, item2, ...

                            item

                                     字符串:用引號引用;

                                               print "hello", "world"

                                     變量:顯示變量的值;

                                               print name

                                               引用變量:直接使用變量名

                                     數值:無須加引號

                   要點:

                            (1) item之間需要使用逗號分隔;而輸出時的分隔符爲默認爲空白字符;

                            (2) 輸出的各item可以爲字符串或數值、當前記錄的字段($#)、變量或awk的表達式;數值會被隱式轉換爲字符串進行輸出;

                            (3) print後面的item省略時,相當於運行“print $0”,用於輸出整行;

                            (4) 輸出空白字符:print " "

2、變量

         內建變量,自定義變量

2.1 內置變量

AWK的內建變量包括域變量,例如$1, $2, $3,以及$0。這些變量給出了記錄中域的內容。 內建變量也包括一些其他變量:

NR:已輸入記錄的條數。

FNR:行數,各文件單獨計數。

NF:當前記錄中域的個數。記錄中最後一個域可以以$NF的方式引用。print NF  每行有幾個字段,print $NF  顯示每一行的最後一個字段

FILENAME:當前輸入文件的文件名。

FS:“域分隔符”,用於將輸入記錄分割成域。其默認值爲“空白字符”,即空格和製表符。FS可以替換爲其它字符,從而改變域分隔符。-v FS="[ ,:.]"

RS:當前的“記錄分隔符”。默認狀態下,輸入的每行都被作爲一個記錄,因此默認記錄分隔符是換行符。

OFS:“輸出域分隔符”,即分隔print命令的參數的符號。其默認值爲空格。

ORS:“輸出記錄分隔符”,即每個print命令之間的符號。其默認值爲換行符。

OFMT:“輸出數字格式”(Format for numeric output),其默認值爲"%.6g"

ARGCawk命令行中的參數的個數。

ARGV:數組,保存了命令行參數本身。

2.2 自定義變量

         (1) -v VAR_NAME=VALUE

                   變量名區分字符大小寫;

         (2) program中自定義變量

                   # awk 'BEGIN{FS=":";f1=3}{print $f1}' /etc/passwd

f1賦值一次一直使用

每讀取一行f1賦一次值

3awk的輸出命令之二:printf

         語法:printf FORMAT(格式),item1,item2,...

         要點:

                   (1) 必須提供FORMAT

                   (2) print語句不同,printf不會自動換行,需要顯式指定換行符:\n

                   (3) FORMAT中需要分別爲後面的每個item指定一個格式符,否則item則無法顯示;   

         格式符:都以%開頭,後跟單個字符;

                   %c: 顯示字符的ASCII碼;

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

                   %e, %E: 科學計數法顯示數值;

                   %f:顯示爲浮點數;

                   %g, %G:以科學計數法或浮點數格式顯示數值;

                   %s: 顯示爲字符串;

                   %u:顯示無符號整數;

                   %%: 顯示%符號自身;

         修飾符:

                   #[.#]

                            左邊的#:用於指定顯示寬度;

                            右邊的#: 顯示精度;

                   +:顯示數值符號

                   -:左對齊

4、操作符

         算術操作符:

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

                   -x: 負值

                   +x: 轉換爲數值

         字符操作符:字符串連接

         賦值操作符:

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

                   ++, --

         比較操作符:

                   >, >=, <, <=, ==, !=

         模式匹配操作符:

                   ~:是否能由右側指定的模式所匹配;

                   !~:是否不能由右側指定模式所匹配;

         邏輯操作符:

                   &&:與運算

                   ||: 或運算

         條件表達式:

                   selector?if-true-expression:if-false-expression

                   # awk -F: '{$3>=500?usertype="Common User":usertype="Sysadmin or Sysuser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd

         函數調用:

                   function_name(argu1, argu2, ...)

5PATTERN模式

(1)    empty:空模式,匹配所有行;

         (2) /Regular Expression/(正則表達式):僅將ACTION應用於能夠被Regular Expression所匹配到的行;

                   例如:awk -F: '/^[ab]/{print $1,$3}' /etc/passwd

         (3) relational expression:關係表達式,即結果爲“真”、“假”的表達式, 或者其結果能類同於“真”或“假”的表達;一般來說,其結果爲非0數值或非空字符串即可類同爲“真”,否則,則類同爲“假”;

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

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

         (4) line ranges:行範圍,類似sedvim中的地址定界方式

                   startline,endline

                   此方式我沒有試驗成功,待定

         (5) BEGIN/END:兩個特殊模式

                   BEGIN:在文件格式化操作開始之前事先執行的一次操作;通常用於輸出表頭或做出一個預處理操作;

                   END:在文件格式操作完成之後,命令退出之前執行的一次操作;通常用於輸出表尾或做出清理操作;

6、常用ACTION

         (1) EXPRESSIONS:例如變量賦值

         (2) Control Statements:控制語句,如if, while等;

         (3) Compound Statements:複合語句

         (4) input statements:輸入語句

         (5) output statements:輸出語句

7、控制語句

         if (condition) { statements } [else { statement }]

         while (condition) { statements }

         do statement while (condition)

         for(expr1;expr2;expr3) { statements }

         for(var in array) { statements }

         switch (expression) {case VALUE or /REGEXP/: statement; ...; default: statementN}

         break

         continue

         delete array[index]

         delete array

         exit [ expression ]

         { statements }

 

         7.1 if-else

                   語法:if (condition) statement [ else statement ]

                            if (condition) {statements} [else {statements}]

                                               ~]# awk -F: '{if ($3>=500) print $1,$3}' /etc/passwd

                                               ~]# awk '{if (NF>=6) print NF,$0}' /etc/rc.d/rc.sysinit

                                               ~]# awk -F: '{if ($3>=500) {print $1,"is a common user"} else {print $1,"is a sysadmin or sysuser"}}' /etc/passwd

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

         7.2 while循環

                   語法:while (condition) statement

                            while (condition) {statements}

                            條件爲“真”時循環,爲“假”時退出循環;

                   使用場景:通常用於在當前行的各字段間進行循環;

                   ~]# awk '{i=1;while(i<=NF){if (length($i)>=6) {print $i};i++}}' /etc/issue

         7.3 do-while循環

                   語法:do statement while (condition)

                            do {statements} while (condtion)

                            意義:至少執行一次循環體

         7.4 for循環

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

                            for (expr1;expr2;expr3) {statements}

                   for (variable assignment;codition;iteration process) {for-body}

                   # awk '{for(i=1;i<=NF;i++){if(length($i)>=6) print $i}}' /etc/issue

                   第二種用法:用於遍歷數組中的元素

                            for (var_name in array) {for-body}

         7.5 swtich

                   語法:switch (expression) {case VALUE or /REGEXP/: statement; ...; default: statementN}

         7.6 break and continue

                   break [n]:退出當前循環,n是一個數字,用於指定退出幾層循環;

                   continue:提前結束本輪循環而進入下一輪;

         7.7 next

                   提前結束對本行文本的處理,而提前進入下一行的處理操作;

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

8、數組

         關聯數組:array[index-expression]

                   index-expression

                            可以使用任意字符;

                            如果某數組元素事先不存在,則在引用時,awk會自動創建此元素並將其值初始化爲空串;

                                     因此,若要判斷 數組中的某元素是否存在,要使用“index in array”的方式進行判斷;

                            要遍歷數組中的元素,則要使用for (var_name in array)的方式進行;此時,var_name會遍歷array的每個索引,所以,要顯示數組元素的值,要使用array[var_name]

                   weekdays

                            weekdays[mon]="Monday"

                            weekdays[tue]="Tuesday"

                            ...

                   for (i in weekdays):此時,i變量會遍歷weekdays數組的每個索引,即mon, tue,而非元素的值“Monday”或"Tuesday"等;

                   要獲取元素的值:weekdays[i]

9、函數

         內建函數和用戶自定義函數

      9.1 內建函數

                   數值處理:

                            rand():返回01之間的一個隨機數;

                   字符串處理:

                            length([s]):返回指定的字符串的長度;

                            sub(r,s[,t]):基於r所表示的模式來匹配字符串t中的內容,將其第一次被匹配到的內容替換爲s所表示的字符串;

gsub(r,s[,t]):基於r所表示的模式來匹配字符串t中的內容,將其所有被匹配到的內容均替換爲s所表示的字符串;

                            split(s,a[,r]):以r爲分隔符去切割字符串s,並將切割後的結果保存至a表示的數組中;

                                     注意:awk的數組下標從1開始編號

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

                            substr(s,i[,n]):從s所表示的字符串中取子串,取法:從i表示的位置開始,取n個字符;

                   時間類函數:

                            systime():取當前系統時間,結果形式爲時間戳;

      9.2 用戶自定義函數

                   function f_name(p,q) {

                            ...

                   }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章