歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

awk中的函數 使用教程

由於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()的新的種子數,如果沒有指定種子數,就用當天的時間。該函數返回舊的種子值 請參見以下詳細總結

上述的三個函數中,隨機數是我們使用最多的,下面就詳細說說randsrand這兩個函數。

有這麼一段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中提供了兩個字符串替換函數:gsubsub。兩者的區別是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~~~

Copyright © Linux教程網 All Rights Reserved