文本處理三劍客之awk(原創)
AWK是一種優良的文本處理工具,Linux及Unix環境中現有的功能最強大的數據處理引擎之一。這種編程及數據操作語言(其名稱得自於它的創始人阿爾佛雷德·艾侯(Alfred Aho)、彼得·溫伯格(Peter Jay Weinberger)和布萊恩·柯林漢(Brian Wilson Kernighan)姓氏的首個字母)的最大功能取決於一個人所擁有的知識。AWK提供了極其強大的功能:可以進行正則表達式的匹配,樣式裝入、流控制、數學運算符、進程控制語句甚至於內置的變量和函數。它具備了一個完整的語言所應具有的幾乎所有精美特性。實際上AWK的確擁有自己的語言:AWK程序設計語言,三位創建者已將它正式定義為“樣式掃描和處理語言”。它允許您創建簡短的程序,這些程序讀取輸入文件、為數據排序、處理數據、對輸入執行計算以及生成報表,還有無數其他的功能。
在我們的Linux中,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:
1、awk的輸出命令之一: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"。
ARGC:awk命令行中的參數的個數。
ARGV:數組,保存了命令行參數本身。
2.2 自定義變量
(1) -v VAR_NAME=VALUE
變量名區分字符大小寫;
(2) 在program中自定義變量
# awk 'BEGIN{FS=":";f1=3}{print $f1}' /etc/passwd
f1賦值一次一直使用
每讀取一行f1賦一次值
3、awk的輸出命令之二: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, ...)
5、PATTERN模式
(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:行範圍,類似sed或vim中的地址定界方式
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():返回0至1之間的一個隨機數;
字符串處理:
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) {
...
}
文本處理三劍客之awk(原創)