由於awk是腳本語言,沒有高級語言中那些復雜的數據類型定義。在awk中定義變量時,每個變量都有一個字符串類型值和數字類型值,所以,在awk中涉及的函數無非就是算術運算,字符串處理,同時也支持用戶自定義函數。接下來的文章內容將按照以下三部分展開來說:
開始踏上征程。
算術函數基本上都接收數值型參數並返回數值型,常用的算術函數如下:
函數名稱
描述
舉例說明
int(x)
對小數向下取整
awk ‘{print int(4.5), int(4.1), int(4.6)}’,輸出:4 4 4
rand(x)
返回隨機數r,其中0<=r<1
awk ‘{print rand(), rand(), rand()}’,輸出:0.237788 0.291066 0.845814
srand(x)
生成rand()的新的種子數,如果沒有指定種子數,就用當天的時間。該函數返回舊的種子值
請參見以下詳細總結
上述的三個函數中,隨機數是我們使用最多的,下面就詳細說說rand
和srand
這兩個函數。
有這麼一段awk腳本:
BEGIN {
print rand();
print rand();
srand();
print rand();
print rand();}
我們將這段腳本保存為rand.awk。
awk -f rand.awk
運行第一次輸出以下結果:
0.2377880.2910660.01182260.115346
運行第二次輸出以下結果:
0.2377880.2910660.7794110.897179
你會發現,兩次運行的前兩個輸出的隨機數值是一樣的,這也是使用這兩個函數需要注意的地方。如果沒有調用srand
函數,awk在開始執行程序之前默認以某個常量為參數調用srand
,類似於srand(2)
這樣的;這就使得程序在每次運行時都從同一個種子數開始,從而導致了輸出了相同的隨機數。如果我們希望每次運行腳本都輸出不同的隨機數,最好的辦法就是在BEGIN部分調用srand
函數。
在任何一門語言中,字符串的處理都是非常重要的,awk也不例外,現在看看awk中的字符串函數:
函數名稱
描述
gsub(r, s, t)
在字符串t中用字符串s替換正則表達式r匹配的所有字符串。返回替換的個數。如果沒有給出t,默認$0
index(s, t)
返回子串t在字符串s中的位置
length(s)
返回字符串s的長度,當沒有給出s時,返回$0的長度
match(s, r)
如果正則表達式r在s中出現,則返回出現的起始位置;如果在s中沒有出現r,則返回0
split(s, a, sep)
使用字段分隔符sep將字符串s分解到數組a的元素中,返回元素的個數。如果沒有給出sep,則使用FS。數組分隔和字段分隔采用同樣的方式
sprintf
格式化輸出
sub(r, s, t)
在字符串t中用s替換正則表達式r的首次匹配。如果成功則返回1,否則返回0,如果沒有給出t,默認為$0
substr(s, p, n)
返回字符串s中從位置p開始最大長度為n的子串。如果沒有給出n,返回從p開始剩余的字符串
tolower(s)
將字符串s中的所有大寫字符轉換為小寫,並返回新串,原字符串並不會被改變
toupper(s)
將字符串s中的所有小寫字符轉換為大寫,並返回新串,原字符串並不會被改變
在awk中提供了兩個字符串替換函數:gsub
和sub
。兩者的區別是gsub
是全局替換,而sub
只替換第一次匹配的內容。
測試數據:Jelly:26:12474125874:04713365412:0081245:Jelly{
# 將每行上匹配"Jelly"的字符串全部替換為"JellyThink"
if (gsub(/Jelly/, "JellyThink"))
print # 輸出:JellyThink:26:12474125874:04713365412:0081245:JellyThink
# 將第一個匹配"JellyThink"的字符串替換為"Jelly"
if (sub(/JellyThink/, "Jelly"))
print # 輸出:Jelly:26:12474125874:04713365412:0081245:JellyThink
# 將所有大寫字符轉換成小寫
print tolower($0) # 輸出:jelly:26:12474125874:04713365412:0081245:jellythink
# 將所有小寫字符轉換成大寫
print toupper($0) # 輸出:JELLY:26:12474125874:04713365412:0081245:JELLYTHINK
# 返回"T"字符的位置,只能返回字符的位置
print index($0, "T")
# 將$0進行分割,並計算每個字段的長度,輸出如下:
# [1]=Jelly , 長度:5
# [2]=26 , 長度:2
# [3]=12474125874 , 長度:11
# [4]=04713365412 , 長度:11
# [5]=0081245 , 長度:7
# [6]=JellyThink , 長度:10
n = split($0, field, ":")
for (i=1; i<=n; ++i)
{
value=sprintf("[%d]=%-12s, 長度:%d", i, field[i], length(field[i]));
print value
}
if (location = match($0, reg))
{
printf("在%d位置匹配到了%s\n", location, reg)
}
else
{
printf("很抱歉,沒有匹配到了%s\n", reg)
}}
讓人進行DIY,總是能讓人感到興奮,在awk中,我們也可以自定義我們自己的函數,在awk中定義函數的寫法如下:
function name(parameter-list){
statements
}
其中parameter-list是用逗號分隔的參數列表,當函數被調用時,它們被作為參數傳遞到函數中。接下來使用一個簡單的例子來說明自定義函數的使用:
測試數據:HelloWorld# 定義函數function insert(string, pos, ins){
before = substr(string, 1, pos)
after = substr(string, pos + 1)
return before ins after
}# 腳本主體{
print insert($0, 5, "JellyThink")
print before #輸出:Hello
print after #輸出:World
print $0 #輸出:HelloWorld}
在腳本的主體部分,我們打印before和after的值時,發現是可以輸出的。這裡有一點需要注意。
awk中,函數中定義的變量,默認是全局的,而傳遞的參數都是值傳遞,也就是說即使在函數內部修改了傳遞進來的參數的值,在函數外部,該參數的值是不會發生改變的。這到和Lua有幾分相像。
再看這樣的寫法:
測試數據:HelloWorld# 定義函數function insert(string, pos, ins, before, after){
before = substr(string, 1, pos)
after = substr(string, pos + 1)
return before ins after
}# 腳本主體{
print insert($0, 5, "JellyThink")
print before #輸出:<空>
print after #輸出:<空>
print $0 #輸出:HelloWorld}
現在明白了麼?在工作中寫awk函數時,需要注意以下兩點:
總結這麼一篇文章不容易,又要想好怎麼排版寫這篇總結,又要去驗證文章中的每一段代碼,這篇文章和《玩玩awk》這篇,在十月初就已經動手開始寫了,後來折騰阿裡雲,浪費了不少時間,還好,今天終於寫完了。不容易!!!Fighting~~~