簡介
awk是一個強大的文本分析工具,相對於grep的尋找,sed的編輯,awk在其對資料分析並產生報告時,顯得尤為強大。簡單來說awk就是把檔案逐行的讀入,以空格為預設分隔符號將每行切片,切開的部分再進行各種分析處理。
awk有3個不同版本: awk、nawk和gawk,未作特別說明,一般指gawk,gawk 是 AWK 的 GNU 版本。
awk其名稱得自於它的創始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首個字母。實際上 AWK 的確擁有自己的語言: AWK 程式設計語言 , 三位建立者已將它正式定義為“樣式掃描和處理語言”。它允許您建立簡短的程式,這些程式讀取輸入檔案、為資料排序、處理資料、對輸入執行計算以及產生報表,還有無數其他的功能。
使用方法
awk '{pattern + action}' {filenames}
儘管操作可能會很複雜,但文法總是這樣,其中 pattern 表示 AWK 在資料中尋找的內容,而 action 是在找到匹配內容時所執行的一系列命令。花括弧({})不需要在程式中始終出現,但它們用於根據特定的模式對一系列指令進行分組。 pattern就是要表示的Regex,用斜杠括起來。
awk語言的最準系統是在檔案或者字串中基於指定規則瀏覽和抽取資訊,awk抽取資訊後,才能進行其他文本操作。完整的awk指令碼通常用來格式化文字檔中的資訊。
通常,awk是以檔案的一行為處理單位的。awk每接收檔案的一行,然後執行相應的命令,來處理文本。
調用awk
有三種方式調用awk
說明:
awk被設計用於資料流,能夠對列和行進行操作。而sed更多的是匹配,進行替換和刪除。
awk有很多內建的功能,比如數組,函數等。靈活性是awk的最大優勢。
awk的結構
awk '
BEGIN{ print "start"}
pattern { commands }
END{ print "end"}'
file
為了偏於觀看,我打了斷行符號,實際上是一行
一個awk指令碼通常是3部分
1. BEGIN語句塊
2. 能夠使用模式比對的通用語句塊
3. END語句塊
他們任何一部分都可以不出現在指令碼中。指令碼通常包含在雙引號或者單引號內。
例如:
awk 'BEGIN{i=0}{i++}END{print i}' filename
工作原理
awk命令的工作方式如下:
1. 執行BEGIN{commands}語句塊中的語句
2. 從檔案或者stdin中讀取一行,然後執行pattern{commands}. 迭代直到全部讀取完畢
3. 最後執行END{commands}語句塊
再次提醒,他們任何一部都可以沒有
而awk的功能也遠不止如此
入門執行個體:
複製代碼 代碼如下:
echo | awk '{var1="v1";var2="v2";var3="v3"; print var1,var2,var3;}'
列印: v1 v2 v3
解釋:逗號為定界符(分隔字元)
echo | awk '{var1="v1";var2="v2";var3="v3"; print var1"-"var2"-"var3;}'
列印v1-v2-v3
解釋:雙引號為串連符
其他任何符號,都不能正常輸出v1,v2,v3
解讀--help(一個非常龐大複雜的協助文檔,官方用了410頁的篇幅PDF來介紹,如果我隻言片語,你信我自己都不信。。)
用法: awk [POSIX 或 GNU 風格選項] -f 指令檔 [--] 檔案 ...
用法: awk [POSIX 或 GNU 風格選項] [--] '程式' 檔案 ...
POSIX 選項: GNU 長選項:
-f 指令檔 --file=指令檔
-F fs --field-separator=fs
指定輸入文本分隔字元,fs是一個字串或者是一個Regex,
-v var=val --assign=var=val
將外部變數值付給var
-m[fr] val
-O --optimize
啟用一些最佳化程式的內部表示。
-W compat --compat
在相容模式下運行awk。所以gawk的行為和標準的awk完全一樣,所有的awk擴充都被忽略。
-W copyleft --copyleft
列印簡短的著作權資訊
-W copyright --copyright
列印短版的通用公用許可證,然後退出
-W dump-variables[=file] --dump-variables[=file]
列印全域變數,其類型,提交的最終值的排序列表。
-W exec=file --exec=file
與-f類似,但與他有兩點不同,(我回頭把相關文檔上傳,太長)
-W gen-po --gen-po
(內容太多)
-W help --help 列印協助
-W lint[=fatal] --lint[=fatal]
警告可疑或不移植到其他的awk實現的結構
-W lint-old --lint-old
列印關於不能向傳統unix平台移植的結構的警告
-W non-decimal-data --non-decimal-data
啟用自動輸入資料的解釋,八進位和十六進位值
-W profile[=file] --profile[=file]
啟用awk程式剖析
-W posix --posix
在嚴格意義上的POSIX模式運作。
-W re-interval --re-interval
允許間隔運算式在Regex上
-W source=program-text --source=program-text
-W traditional --traditional
傳統的Unix awk的Regex匹配
-W usage --usage
-W use-lc-numeric --use-lc-numeric
解析數字輸入時,強制使用的語言環境中的小數點字元
資料
-W version --version
提交錯誤報表請參考“gawk.info”中的“Bugs”頁,它位於列印版本中的“Reporting
Problems and Bugs”一節
注意:gawk是awk的GNU版本,即使help ,在ubuntu下也需要先安裝gawk
這回我們就不解讀了,為了增加大家的資訊和樂趣,先來點基本的:
部分特殊變數:
NR: 表示記錄數量,在執行過程中對應於行號
NF:表示欄位數量,在執行過程中對應於當前行的欄位數
$0: 這個變數包含執行過程中當前行的常值內容
$1: 第一個欄位的常值內容
$2: 第二個欄位的常值內容
例子:
例1.
複製代碼 代碼如下:
echo -e "line1 f2 f3\nline2 f4 f5\nline3 f6 f7"|\#這個\是在視窗中寫多行命令用的
awk '{
print "Line no:"NR",No of fields:"NF, "$0="$0,"$1="$1,"$2="$2,"$3="$3
}'
小注一下:$1是列印第一個,$NF列印最後一個欄位,$(NF-1)列印倒數第二個
例2.
seq 5 | awk 'BEGIN{ sum=0;print "Summation:"}{print $1"+";sum+=1}END{print "==";print sum}'
這個例子用到了基本格式。
BEGIN中 初始化了sum,列印Summation
中間模組列印了第一列,然後給sum+1
END中列印了sum
例3. 關於-v 外部變數
複製代碼 代碼如下:
$ VAR=10000
$echo | awk –v VARIABLE=$VAR'{print VARABLE}'
還有另一種靈活的方法可以將多個外部變數傳遞給awk,例如:
複製代碼 代碼如下:
$var1="value1" var2="value2"
$echo | awk '{print v1,v2}' v1=$var1 v2=$var2
如果來自檔案
awk '{print v1,v2}' v1=$var1 v2=$var2 filename
例4
$awk 'NR < 5' #行號小於5
$awk 'NR==1,NR==4' #行號在1到5之間的行
$awk '/linux/' #包含樣式linux的行(可以用Regex指定樣式)
$awk '!/linux/' #不包含樣式linux的行
這次先寫這些,爭取在花2個篇幅能把awk做個比較全面的認識。
awk補充
之前我們學習了awk基本入門,我驚喜的發現有awk一篇詳細文章,有寫念頭,不能全部轉載,轉化成自己的方式來寫一些。
主講內建變數和部分字串函數
內建變數(有翻譯特殊變數和環境變數,按照官方翻譯為內建變數)
變數 |
說明 |
$n |
目前記錄的第n個欄位,欄位間由FS分隔。 |
$0 |
完整的輸入記錄。 |
ARGC |
命令列參數的數目。 |
ARGIND |
命令列中當前檔案的位置(從0開始算)。 |
ARGV |
包含命令列參數的數組。 |
BINMODE |
在非POSIX系統上,這個變數指定的所有I / O使用二進位模式 |
CONVFMT |
數字轉換格式(預設值為%.6g) |
ENVIRON |
環境變數關聯陣列。 |
ERRNO |
最後一個系統錯誤的描述。 |
FIELDWIDTHS |
欄位寬度列表(用空格鍵分隔)。 |
FILENAME |
當前檔案名稱。 |
FNR |
同NR,但相對於當前檔案 |
FPAT |
這是一個Regex(字串),告訴gawk基於匹配Regex的文本來建立欄位 |
FS |
欄位分隔符號(預設是任何空格)。 |
IGNORECASE |
如果為真,則進行忽略大小寫匹配。 |
LINT |
當這個變數為真(非零或非空),gawk的行為猶如"--lint"命令列選項 |
NF |
目前記錄中的欄位數。 |
NR |
目前記錄數。 |
OFMT |
數位輸出格式(預設值是%.6g)。 |
OFS |
輸出欄位分隔符號(預設值是一個空格)。 |
ORS |
輸出記錄分隔字元(預設值是一個分行符號)。 |
PROCINFO |
這個數組的元素提供訪問運行awk程式的資訊 |
RLENGTH |
由match函數所匹配的字串的長度。 |
RS |
記錄分隔字元(預設是一個分行符號)。 |
RT |
每次一條記錄被讀取的設定 |
RSTART |
由match函數所匹配的字串的第一個位置。 |
SUBSEP |
數組下標分隔字元(預設值是\034)。 |
TEXTDOMAIN |
此變數用於程式的國際化 |
藍色為新增加的內建變數。
簡單舉例:
1.
01.sed 1q /etc/passwd | awk '{ FS = ":"; print $1 }'
列印密碼第一行,用冒號分隔字元
2.
複製代碼 代碼如下:
awk 'END{print FILENAME}' awk.txt
列印文本FILENAME
3. seq 100 | awk 'NR==4,NR==6'
列印4到6行
再介紹幾個awk內建的字串函數,也講一部分。
length(string):
返回字串的長度
index(string,serch_string):
返回search_string在字串中出現的位置
split(string,array,delimiter):
用定界符產生一個字串列表,並將該列表存入數組
substr(string,array,delimiter):
在字串中用字元起止便宜量產生子串,並返回該子串
sub(regex,replacement_str,string):
將Regex匹配到的第一處內容替換成replacement_str
gsub(regex,replacement_str,string):
和sub()類似。不過該函數會替換Regex匹配到的所有內容
match(regex,string):
檢查Regex是否能夠匹配字串。如果能夠匹配,返回非0值;否則,返回0.match()有兩個相關的特殊變數,分別是RSTART喝RLENGTH。變數RSTART包含Regex所匹配內容的其實位置,而變數RLENGTH包含Regex所匹配內容的長度。
舉例:
1.$ awk '{ sub(/test/, "mytest"); print }' testfile
在整個記錄中匹配,替換隻發生在第一次匹配發生的時候
2.$ awk '{ sub(/test/, "mytest"); $1}; print }' testfile
在整個記錄的第一個域中進行匹配,替換隻發生在第一次匹配發生的時候
3.$ awk '{ print index("test", "mytest") }' testfile
執行個體返回test在mytest的位置,結果應該是3
4.$ awk '{ print length( "test" ) }'
執行個體返回test字串的長度。
awk補充二
這節可能要寫的比較粗了,時間太少。
一. 內建函數
注意一種約定俗稱文法習慣: [a]代表a可選.
數字函數(Numeric Functions)
函數名 |
說明 |
atan2(y,x) |
返回y/x弧的反正切 |
cos(x) |
返回x的餘弦 |
exp(x) |
返回x的指數 |
int(x) |
返回最靠近的整數,風向標指向0 |
log(x) |
返回x的自然對數 |
rand() |
返回隨機數 |
sin(x) |
返回x的正弦 |
sqrt(x) |
返回x的正平方根 |
srand([x]) |
產生隨機數,可以設定起點 |
字串操作函數(String-Manipulation Functions)
注意:藍色部分為gawk特有,awk沒有此函數功能。
函數名 |
說明 |
asort(source [, dest [, how ] ]) |
返回數組元素數(內容較多) |
asorti(source [, dest [, how ] ]) |
同asort,(有細微差別) |
gensub(regexp, replacement, how [, target]) |
搜尋RegexRegExp匹配的regexp |
gsub(regexp, replacement [, target]) |
將Regex匹配的第一處內容替換成replacement_str |
index(in, find) |
返回find在字串in中出現的位置 |
length([string]) |
string 中的字元數 |
match(string, regexp [, array]) |
檢查Regex能否匹配字串 |
patsplit(string, array [, fieldpat [, seps ] ]) |
劃分件到由fieldpat定義的字串,並儲存在array裡,分隔字串存在在seps數組 |
split(string, array [, fieldsep [, seps ] ]) |
用定界符產生一個字串列表,並將該列表存入數組 |
sprintf(format, expression1, ...) |
列印 |
strtonum(str) |
字元轉轉換成數字 |
sub(regexp, replacement [, target]) |
將Regex匹配到的第一處內容替換成replacement |
substr(string, start [, length]) |
分割字串,根據其實位置和長度 |
tolower(string) |
轉換成小寫 |
toupper(string) |
轉換成大寫 |
輸入輸出函數(Input/Output Functions)
函數 |
說明 |
close(filename [, how]) |
關閉檔案輸入輸出資料流 |
fflush([filename]) |
重新整理與檔案名稱相關的任何緩衝輸出 |
system(command) |
執行作業系統命令,傳回值給awk程式 |
時間函數(Time Functions)
函數 |
說明 |
mktime(datespec) |
datespec為時間戳記格式,與systime()格式一樣 |
strftime([format [, timestamp [, utc-flag]]]) |
格式化timestamp的內容,返回日期格式 |
systime() |
返回系統時間,精確到秒 |
位操作函數(Bit-Manipulation Functions)
函數 |
說明 |
and(v1, v2) |
v1,v2的與操作結果 |
compl(val) |
val的反碼 |
lshift(val, count) |
返回val左移count位的值 |
or(v1, v2) |
v1,v2的或操作 |
rshift(val, count) |
返回val右移count位的值 |
xor(v1, v2) |
返回v1,v2的異或的值 |
擷取類型資訊(Getting Type Information)
函數 |
說明 |
isarray(x) |
如果x是數組,返回true.否則false |
字串轉換函式(String-Translation Functions)
函數 |
說明 |
bindtextdomain(directory [, domain]) |
設定awk要搜尋資訊的目錄和域 |
dcgettext(string [, domain [, category]]) |
返回的字串string 翻譯文本域domain 的語言環境類別category |
dcngettext(string1, string2, number [, domain [, category]]) |
返回string1和string2的翻譯數量的複數形式,string1,string2在語言環境類別的文本域裡 |
內建函數還有些進階特性,等許多執行個體,以後有機會補充。
二. 自訂函數
格式入下:
複製代碼 代碼如下:
function name([parameter-list])
{
body-of-function
}
如:
複製代碼 代碼如下:
function myprint(num)
{
printf "%6.3g\n", num
}
awk這個命令還有很多功能,打算就唯寫這麼多了。以後可能更多在一些例子裡,與其他命令結合時會提到。