精通awk系列(20):awk數組用法詳解

来源:https://www.cnblogs.com/f-ck-need-u/archive/2020/02/29/12382038.html
-Advertisement-
Play Games

回到: "Linux系列文章" "Shell系列文章" "Awk系列文章" 數組 awk數組特性: awk的數組是關聯數組(即key/value方式的hash數據結構),索引下標可為數值(甚至是負數、小數等),也可為字元串 在內部,awk數組的索引全都是字元串,即使是數值索引在使用時內部也會轉換成字 ...



回到:


數組

awk數組特性:

  • awk的數組是關聯數組(即key/value方式的hash數據結構),索引下標可為數值(甚至是負數、小數等),也可為字元串
    • 在內部,awk數組的索引全都是字元串,即使是數值索引在使用時內部也會轉換成字元串
    • awk的數組元素的順序和元素插入時的順序很可能是不相同的
  • awk數組支持數組的數組

awk訪問、賦值數組元素

arr[idx]
arr[idx] = value

索引可以是整數、負數、0、小數、字元串。如果是數值索引,會按照CONVFMT變數指定的格式先轉換成字元串。

例如:

awk '
  BEGIN{
    arr[1]   = 11
    arr["1"] = 111
    arr["a"] = "aa"
    arr[-1]  = -11
    arr[4.3] = 4.33
# 本文來自駿馬金龍:www.junmajinlong.com
    print arr[1]     # 111
    print arr["1"]   # 111
    print arr["a"]   # aa
    print arr[-1]    # -11
    print arr[4.3]   # 4.33
  }
'

通過索引的方式訪問數組中不存在的元素時,會返回空字元串,同時會創建這個元素並將其值設置為空字元串

awk '
  BEGIN{
    arr[-1]=3;
    print length(arr);  # 1
    print arr[1];
    print length(arr)   # 2
  }'

awk數組長度

awk提供了length()函數來獲取數組的元素個數,它也可以用於獲取字元串的字元數量。還可以獲取數值轉換成字元串後的字元數量。

awk 'BEGIN{arr[1]=1;arr[2]=2;print length(arr);print length("hello")}'

awk刪除數組元素

  • delete arr[idx]:刪除數組arr[idx]元素
    • 刪除不存在的元素不會報錯
  • delete arr:刪除數組所有元素
$ awk 'BEGIN{arr[1]=1;arr[2]=2;arr[3]=3;delete arr[2];print length(arr)}'
2

awk檢測是否是數組

isarray(arr)可用於檢測arr是否是數組,如果是數組則返回1,否則返回0。

typeof(arr)可返回數據類型,如果arr是數組,則其返回"array"。

awk 'BEGIN{
    arr[1]=1;
    print isarray(arr);
    print (typeof(arr) == "array")
}'

awk測試元素是否在數組中

不要使用下麵的方式來測試元素是否在數組中:

if(arr["x"] != ""){...}

這有兩個問題:

  • 如果不存在arr["x"],則會立即創建該元素,並將其值設置為空字元串
  • 有些元素的值本身就是空字元串

應當使用數組成員測試操作符in來測試:

# 註意,idx不要使用index,它是一個內置函數
if (idx in arr){...}

它會測試索引idx是否在數組中,如果存在則返回1,不存在則返回0。

awk '
    BEGIN{
    # 本文來自駿馬金龍:www.junmajinlong.com
        arr[1]=1;
        arr[2]=2;
        arr[3]=3;

        arr[1]="";
        delete arr[2];

        print (1 in arr);  # 1
        print (2 in arr);  # 0
    }'

awk遍曆數組

awk提供了一種for變體來遍曆數組:

for(idx in arr){print arr[idx]}

因為awk數組是關聯數組,元素是不連續的,也就是說沒有順序。遍歷awk數組時,順序是不可預測的。

例如:

# 本文來自駿馬金龍:www.junmajinlong.com
awk '
    BEGIN{
        arr["one"] = 1
        arr["two"] = 2
        arr["three"] = 3
        arr["four"] = 4
        arr["five"] = 5

        for(i in arr){
            print i " -> " arr[i]
        }
    }
'

此外,不要隨意使用for(i=0;i<length(arr);i++)來遍曆數組,因為awk數組是關聯數組。但如果已經明確知道數組的所有元素索引都位於某個數值範圍內,則可以使用該方式進行遍歷。

例如:

# 本文來自駿馬金龍:www.junmajinlong.com
awk '
    BEGIN{
        arr[1] = "one"
        arr[2] = "two"
        arr[3] = "three"
        arr[4] = "four"
        arr[5] = "five"
        arr[10]= "ten"

        for(i=0;i<=10;i++){
            if(i in arr){
                print arr[i]
            }
        }
    }
'

awk複雜索引的數組

在awk中,很多時候單純的一個數組只能存放兩個信息:一個索引、一個值。但在一些場景下,這樣簡單的存儲能力在處理複雜需求的時候可能會捉襟見肘。

為了存儲更多信息,方式之一是將第3份、第4份等信息全部以特殊方式存放到值中,但是這樣的方式在實際使用過程中並不方便,每次都需要去分割值從而取出各部分的值。

另一種方式是將第3份、第4份等信息存放在索引中,將多份數據組成一個整體構成一個索引。

gawk中提供了將多份數據信息組合成一個整體當作一個索引的功能。預設方式為arr[x,y],其中x和y是要結合起來構建成一個索引的兩部分數據信息。逗號稱為下標分隔符,在構建索引時會根據預定義變數SUBSEP的值將多個索引組合起來。所以arr[x,y]其實完全等價於arr[x SUBSEP y]

例如,如果SUBSEP設置為"@",那麼arr[5,12] = 512存儲時,其真實索引為5@12,所以要訪問該元素需使用arr["5@12"]

SUBSEP的預設值為\034,它是一個不可列印的字元,幾乎不可能會出現在字元串當中。

如果我們願意的話,我們也可以自己將多份數據組合起來去構建成一個索引,例如arr[x" "y]。但是awk提供了這種更為簡便的方式,直接用即可。

為了測試這種複雜數組的索引是否在數組中,可以使用如下方式:

arr["a","b"] = 12
if (("a", "b") in arr){...}

例如,順時針倒轉下列數據:

1 2 3 4 5 6
2 3 4 5 6 1
3 4 5 6 1 2
4 5 6 1 2 3

結果:
4 3 2 1
5 4 3 2
6 5 4 3
1 6 5 4
2 1 6 5
3 2 1 6
{
  nf = NF
  nr = NR
  for(i=1;i<=NF;i++){
    arr[NR,i] = $i
  }
}

END{
  for(i=1;i<=nf;i++){
    for(j=nr;j>=1;j--){
      if(j%nr == 1){
        printf "%s\n", arr[j,i]
      }else {
        printf "%s ", arr[j,i]
      }
    }
  }
}

awk子數組

子數組是指數組中的元素也是一個數組,即Array of Array,它也稱為子數組(subarray)。

awk也支持子數組,在效果上即是嵌套數組或多維數組。

a[1][1] = 11
a[1][2] = 12
a[1][3] = 13
a[2][1] = 21
a[2][2] = 22
a[2][3] = 23
a[2][4][1] = 241
a[2][4][2] = 242
a[2][4][1] = 241
a[2][4][3] = 243

通過如下方式遍歷二維數組:

for(i in a){
    for (j in a[i]){
        if(isarray(a[i][j])){
            continue
        }
        print a[i][j]
    }
}

awk指定數組遍歷順序

由於awk數組是關聯數組,預設情況下,for(idx in arr)遍曆數組時順序是不可預測的。

但是gawk提供了PROCINFO["sorted_in"]來指定遍歷的元素順序。它可以設置為兩種類型的值:

  • 設置為用戶自定義函數
  • 設置為下麵這些awk預定義好的值:
    • @unsorted:預設值,遍歷時無序
    • @ind_str_asc:索引按字元串比較方式升序遍歷
    • @ind_str_desc:索引按字元串比較方式降序遍歷
    • @ind_num_asc:索引強制按照數值比較方式升序遍歷。所以無法轉換為數值的字元串索引將當作數值0進行比較
    • @ind_num_desc:索引強制按照數值比較方式降序遍歷。所以無法轉換為數值的字元串索引將當作數值0進行比較
    • @val_type_asc:按值升序比較,此外數值類型出現在前面,接著是字元串類型,最後是數組類(即認為num<str<arr)
    • @val_type_desc:按值降序比較,此外數組類型出現在前面,接著是字元串類型,最後是數值型(即認為num<str<arr)
    • @val_str_asc:按值升序比較,數值轉換成字元串再比較,而數組出現在尾部(即認str<arr)
    • @val_str_desc:按值降序比較,數值轉換成字元串再比較,而數組出現在頭部(即認str<arr)
    • @val_num_asc:按值升序比較,字元串轉換成數值再比較,而數組出現在尾部(即認num<arr)
    • @val_num_desc:按值降序比較,字元串轉換成數值再比較,而數組出現在頭部(即認為num<arr)

例如:

awk '
  BEGIN{
    arr[1] = "one"
    arr[2] = "two"
    arr[3] = "three"
    arr["a"] ="aa"
    arr["b"] ="bb"
    arr[10]= "ten"

    #PROCINFO["sorted_in"] = "@ind_num_asc"
    #PROCINFO["sorted_in"] = "@ind_str_asc"
    PROCINFO["sorted_in"] = "@val_str_asc"
    for(idx in arr){
      print idx " -> " arr[idx]
    }
}'

a -> aa
b -> bb
1 -> one
2 -> two
3 -> three
10 -> ten

# 本文來自駿馬金龍:www.junmajinlong.com

如果指定為用戶自定義的排序函數,其函數格式為:

function sort_func(i1,v1,i2,v2){
    ...
    return <0;0;>0
}

其中,i1和i2是每次所取兩個元素的索引,v1和v2是這兩個索引的對應值。

如果返回值小於0,則表示i1在i2前面,i1先被遍歷。如果等於0,則表示i1和i2具有等值關係,它們的遍歷順序不可保證。如果大於0,則表示i2先於i1被遍歷。

例如,對數組元素按數值大小比較來決定遍歷順序。

awk '
function cmp_val_num(i1, v1, i2, v2){
  if ((v1 - v2) < 0) {
    return -1
  } else if ((v1 - v2) == 0) {
    return 0
  } else {
    return 1
  }
  # return (v1-v2)
}

NR > 1 {
  arr[$0] = $4
}

END {
  PROCINFO["sorted_in"] = "cmp_val_num"
  for (i in arr) {
    print i
  }
}' a.txt

再比如,按數組元素值的字元大小來比較。

function cmp_val_str(i1,v1,i2,v2) {
    v1 = v1 ""
    v2 = v2 ""
    if(v1 < v2){
        return -1
    } else if(v1 == v2){
        return 0
    } else {
        return 1
    }
    # return (v1 < v2) ? -1 : (v1 != v2)
}

NR>1{
    arr[$0] = $2
}

END{
    PROCINFO["sorted_in"] = "cmp_val_str"
    for(line in arr)
    {
        print line
    }
}

再比如,對元素值按數值升序比較,且相等時再按第一個欄位ID進行數值降序比較。

awk '
function cmp_val_num(i1,v1,i2,v2,    a1,a2) {
    if (v1<v2) {
        return - 1
    } else if(v1 == v2){
        split(i1, a1, SUBSEP)
        split(i2, a2, SUBSEP)
        return a2[2] - a1[2]
    } else {
        return 1
    }
}

NR>1{
    arr[$0,$1] = $4
}

END{
    PROCINFO["sorted_in"] = "cmp_val_num"
    for(str in arr){
        split(str, a, SUBSEP)
        print a[1]
    }
}

' a.txt

上面使用的arr[x,y]來存儲額外信息,下麵使用arr[x][y]多維數組的方式來存儲額外信息實現同樣的排序功能。

NR>1{
  arr[NR][$0] = $4
}

END{
  PROCINFO["sorted_in"] = "cmp_val_num"
  for(nr in arr){
    for(line in arr[nr]){
      print line
    }
  # 本文來自駿馬金龍:www.junmajinlong.com
  }
}

function cmp_val_num(i1,v1,i2,v2,   ii1,ii2){
  # 獲取v1/v2的索引,即$0的值
  for(ii1 in v1){ }
  for(ii2 in v2){ }

  if(v1[ii1] < v2[ii2]){
    return -1
  }else if(v1[ii1] > v2[ii2]){
    return 1
  }else{
    return (i2 - i1)
  }
}

此外,gawk還提供了兩個內置函數asort()和asorti()來對數組進行排序。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • selinux概念 由美國國家安全局(NSA)和SCC聯合開發的,強制訪問控制的安全模塊。2000年以GPL開源,linux2.6內核後集成在內核里。 不啟用selinux時,訪問模式叫:DAC(discretionary access control)自由訪問控制 在DAC模式下的進程能夠訪問哪些 ...
  • 出現這個錯誤時,這多半是你所編譯的項目是在64位機器上生成32位的項目,你需要安裝對應的gcc 32位的庫;此時檢查gcc一定有-m32的存在; 你系統中gcc沒有安裝multilib 庫;使用這個庫可以在64位的機器上產生32位的程式或者庫文件; 你可以選擇:apt install gcc-mul ...
  • 1.SetUID 一.SetUID的功能 SetUID主要是給命令提供一個root許可權,就是命令運行時擁有root用戶許可權,命令運行結束後root許可權消失 passwd cat 二.設定SetUID的方法 4代表SUID chmod 4755 文件名 chmod u+s 文件名 三.取消SetUID ...
  • 1.ACL許可權簡介與開啟 一.ACL許可權是為瞭解決所有者/所屬組/其他人三種身份不足的問題 二.查看分區ACL許可權是否開啟 dumpe2fs命令是查詢指定分區詳細文件系統信息的命令 dumpe2fs h /dev/sda3 Default mount options: user_xattr acl顯 ...
  • 背景 By 魯迅 By 高爾基 說明: 1. Kernel版本:4.14 2. ARM64處理器,Contex A53,雙核 3. 使用工具:Source Insight 3.5, Visio 1. 概述 進程切換:內核將CPU上正在運行的進程掛起,選擇下一個進程來運行。 ARM架構中,CPU上一次 ...
  • 1. Prometheus配置方式有兩種 命令行,用來配置不可變命令參數,主要是Prometheus運行參數,比如數據存儲位置 配置文件,用來配置Prometheus應用參數,比如數據採集,報警對接 不重啟進程配置生效方式也有兩種 對進程發送信號SIGHUP HTTP POST請求,需要開啟 web ...
  • 簡介:Nextcloud是一款開源免費的私有雲存儲網盤項目,可以讓你快速便捷地搭建一套屬於自己或團隊的雲同步網盤,從而實現跨平臺跨設備文件同步、共用、版本控制、團隊協作等功能。它的客戶端覆蓋了Windows、Mac、Android、iOS、Linux 等各種平臺,也提供了網頁端以及 WebDAV介面 ...
  • Windows操作系統的帳號角色許可權 1.Windows操作系統的帳戶: • Windows操作系統好比一間富麗堂皇的宮殿,大門的門鎖是身份和許可權鑒別器,到訪人員是賬戶,鑰匙是驗證其身份和許可權的措施。 <1.>本地系統帳戶,Local System Account 本地管理員帳戶,Local Adm ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...