一:awk爲報告生成器
AWK字段:awk對每行文檔按照分隔符(缺省爲空格指定的話爲-F)把行內的內容切成每個字段。
$0:代表整行。
$1...$N:代表被分割符分開的每個字段。
二:awk基本語法
基本語法: awk [options] 'program' file file ...
awk [options] 'PATTERN{action}' file file ...
輸入選項: -F 指定分割符選項。
awk -F : '{print $1 ,$7}' /etc/passwd #指定以冒號作爲字段分割符。默認是以空格
PATTERN: awk的輸出
print item1, item2, ........
要點: (1) 各項目之間使用逗號分隔,而輸出時則使用輸出分隔符分隔; (2) 輸出的各item可以字符串或數值、當前記錄的字段、變量或awk的表達式;數值會被隱式轉換爲字符串後輸出; (3) print後面item如果省略,相當於print $0輸出整串內容;要想後面輸出空白,使用pirnt " " (在awk中輸出子串要使用雙引號);
遇到awk的錯誤需要注意的幾點
(1)確保整個a w k命令用單引號括起來。 (2)確保命令內所有引號成對出現。 (3)確保用花括號括起動作語句,用圓括號括起條件語句。 (4)可能忘記使用花括號,也許你認爲沒有必要,但a w k不這樣認爲,將按之解釋語法
awk的變量:內置變量,自定義變量
內置變量:輸入時的字段分隔符 (awk的內置變量前要用BEGIN)
awk內置變量 A R G C 命令行參數個數 A R G V 命令行參數排列 E N V I R O N 支持隊列中系統環境變量的使用 FILENAME a w k瀏覽的文件名 F N R 瀏覽文件的記錄數 F S 設置輸入域分隔符,等價於命令行- F選項 N F 瀏覽記錄的域個數 N R 已讀的記錄數 O F S 輸出域分隔符 O R S 輸出記錄分隔符 R S 控制記錄分隔符
FS:Field Seperator, 輸入時的字段分隔符相當於-F # awk 'BEGIN{FS=":"}{print $1,$7}' /etc/passwd #內置變量的引用要用到雙引號 OFS: Output Field Seperator, 輸出時的字段分隔符 # awk 'BEGIN{FS=":";OFS=":"}{print $1,$7}' /etc/passwd #語句與語句之間要用分號分割 (紅色部分) RS:Record Seperator, 輸入行分隔符 # awk 'BEGIN{RS=":"}{print }' /etc/passwd #會把冒號分開的內容當作每一行來處理
ORS: Outpput Row Seperator, 輸出時的行分隔符在一行內容中 awk 'BEGIN{FS=":";ORS=":"}{print $1,$7}' /etc/passwd
NF:Numbers of Field,字段數 #取最後一個字段還可用$NF NR:Numbers of Record, 行數如果後面跟有多個文件的話那麼就是所有文件的一併計數; # awk 'BEGIN{FS=":";OFS=":"}{print NR $1,$7}' /etc/passwd /etc/group
FNR:行數;各文件分別計數; # awk 'BEGIN{FS=":";OFS=":"}{print FNR $1,$7}' /etc/passwd
ARGV:數組,保存命令本身這個字符,awk '{print $0}' 1.txt 2.txt,意味着ARGV[0]保存awk,
# awk 'BEGIN{print ARGV[0],ARGV[1],ARGV[2],ARGC}' /etc/passwd /etc/group
ARGC: 保存awk命令中參數的個數
自定義變量:輸入時的字段分隔符 (awk的內置變量前要用BEGIN
-v var_name=VALUE 變量名區分字符大小寫
(1) 可以program中定義變量;
(2) 可以命令行中通過-v選項自定義變量;
# awk 'BEGIN{a="hello awk"}{print a}' /etc/passwd
#awk 'BEGIN{a="hello awk";print a}' #可以不跟文件 直接輸出hello awk #awk -v a="hello awk" 'BEGIN{print a}' #直接輸出hello awk
awk的printf命令
命令的使用格式:printf format, item1, item2,... #print 後跟的直接打印內容要加上雙引號
要點:
(1) 要指定format;
(2) 不會自動換行;如需換行則需要給出\n
(3) format用於爲後面的每個item指定其輸出格式;
(4) 爲加入t a b鍵,使用t a b鍵速記引用符\ t
format格式的指示符都%開頭,後跟一個字符:
%c: 顯示字符的ASCII碼;
%d, %i: 十進制整數;
%e, %E: 科學計數法顯示數值;
%f: 顯示浮點數;
%g, %G: 以科學計數法格式或浮點數格式顯示數值;
%s: 顯示字符串;
%u: 顯示無符號整數;
%%: 顯示%自身;
修飾符:
#:顯示寬度
-:左對齊
+:顯示數值的符號
.#: 取值精度
# awk -F: '{printf "%15s %-15s\n",$1,$7}' /etc/passwd
# awk 'BEGIN {printf "%f\n",3.1415}' #顯示7個字節
# awk 'BEGIN {printf "%f\n",3.1415926}' #總位數超過8位,小數點後面要進行四捨五入
# awk 'BEGIN {printf "%15.2f\n",3.1415926}' #15.2 表示整體爲15個位寬加小數點後兩位
# awk 'BEGIN {printf "name betle\n-----------"}{print $1"\t",$4}' /etc/passwd
awk輸出重定向
print items > output-file
print items >> output-file
print items | command
特殊文件描述符:
/dev/stdin: 標準輸入
/dev/stdout: 標準輸出
/dev/stderr: 錯誤輸出
awk的操作符
算術操作符: x+y 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?utype="common user":utype="admin or system user";print $1,"is",utype}' /etc/passwd 函數調用: function_name(argu1,argu2)
正則表達式的使用
模式匹配
爲使一域號匹配正則表達式,使用符號‘~’後緊跟正則表達式,也可以用i f語句。a w k中i f後面的條件用()括起來。
cat test.txt M.Tans 5/99 48311 Green 8 40 44 J.Lulu 06/99 48317 green 9 24 26 P.Bunny 02/99 48 Yellow 12 35 28 J.Troll 07/99 4842 Brown-3 12 26 26 L.Tansl 05/99 4712 Brown-2 12 30 28 awk '{if($4~/Brown/) print $0}' test.txt J.Troll 07/99 4842 Brown-3 12 26 26 L.Tansl 05/99 4712 Brown-2 12 30 28 awk '$0 ~ /Brown/' test.txt 此方法也可以得到同樣的結果 J.Troll 07/99 4842 Brown-3 12 26 26 L.Tansl 05/99 4712 Brown-2 12 30 28
精確匹配
假定要使字符串精確匹配,比如說查看學生序號4 8,文件中有許多學生序號包含4 8,如果在f i e l d - 3中模式查詢序號4 8,a w k將返回所有序號帶4 8的記錄:
awk '{if($3~/48/) print $0}' test.txt M.Tans 5/99 48311 Green 8 40 44 J.Lulu 06/99 48317 green 9 24 26 P.Bunny 02/99 48 Yellow 12 35 28 J.Troll 07/99 4842 Brown-3 12 26 26 awk '{if ($3== "48") print $0}' test.txt #準確匹配的內容要用雙引號 P.Bunny 02/99 48 Yellow 12 35 28 awk '{if ($3="48" print $0)}' test.txt M.Tans 5/99 48 Green 8 40 44 J.Lulu 06/99 48 green 9 24 26 P.Bunny 02/99 48 Yellow 12 35 28 J.Troll 07/99 48 Brown-3 12 26 26 L.Tansl 05/99 48 Brown-2 12 30 28 從上面的兩個例子可以看出 “=”和“==”是完全不同的一個是複製,一個是等於
不匹配
假定$4不匹配Brown 都輸出
awk '$4 !~ /Brown/' test.txt M.Tans 5/99 48311 Green 8 40 44 J.Lulu 06/99 48317 green 9 24 26 P.Bunny 02/99 48 Yellow 12 35 28
設置輸入域到域變量名
在a w k中,設置有意義的域名是一種好習慣,在進行模式匹配或關係操作時更容易理解。一般的變量名設置方式爲n a m e = $ n,這裏n a m e爲調用的域變量名, n爲實際域號。例如設置學生域名爲n a m e,級別域名爲b e l t,操作爲n a m e = $ 1 ; b e l t s = $ 4。注意分號的使用,它分隔a w k命令。下面例子中,重新賦值學生名域爲n a m e,級別域爲b e l t s。查詢級別爲Ye l l o w的記錄,並最終打印名稱和級別。
awk '{name=$1;belts=$4;if(belts ~/Yellow/) print name" is belt "belts}' grade.txt P.Bunny is belt Yellow
域值比較
有兩種方式測試一數值域是否小於另一數值域。
1) 在B E G I N中給變量名賦值。
2) 在關係操作中使用實際數值。
通常在B E G I N部分賦值是很有益的,可以在a w k表達式進行改動時減少很多麻煩。
使用關係操作必須用圓括號括起來。
下面的例子查詢所有比賽中得分在2 7點以下的學生。
用引號將數字引用起來是可選的,“2 7”、2 7產生同樣的結果。
awk 'BEGIN{BASELINE="27"} {if ($6<BASELINE) print $0}' grade.txt J.Lulu 06/99 48317 green 9 24 26 J.Troll 07/99 4842 Brown-3 12 26 26
修改數值域或者取值
當在a w k中修改任何域時,重要的一點是要記住實際輸入文件是不可修改的,修改的只是保存在緩存裏的a w k複本。a w k會在變量N R或N F變量中反映出修改痕跡。
爲修改數值域,簡單的給域標識重賦新值,如: $ 1 = $ 1 + 5,會將域1數值加5,但要確保賦值域其子集爲數值型。
修改M . Ta n s l e y的目前級別分域,使其數值從4 0減爲3 9,使用賦值語句$ 6 = $ 6 - 1,當然在實施修改前首先要匹配域名。
awk '{if($1=="M.Tans") {$6=$6-1};print $1,$6,$7}' grade.txt M.Tans 39 44 J.Lulu 24 26 P.Bunny 35 28 J.Troll 26 26 L.Tansl 30 28