Awk 入門/陣列
Awk 也允許使用陣列。那些以前編寫過程式的人已經熟悉陣列。對於那些沒有接觸過陣列的人來說,陣列只是一個儲存多個值的單個變數,類似於列表。命名約定與變數相同,並且,與變數一樣,陣列不需要宣告。
Awk 陣列只能有一維;第一個索引為 1。陣列元素透過索引來識別,索引包含在方括號中。例如
some_array[1] = "Hello" some_array[2] = "Everybody" some_array[3] = "!" print some_array[1], some_array[2], some_array[3]
括號內的數字是索引。它選擇陣列內的特定條目,或元素,然後可以像普通變數一樣建立、訪問或修改它。
這是熟悉 C 風格陣列的人學習新事物的地方。Awk 陣列很有趣,因為它們實際上是關聯陣列。索引實際上是字串,因此關聯陣列更像字典而不是編號列表。例如,陣列可以用來統計一組債務人所欠的錢,如下所示
debts["Kim"] = 50 debts["Roberto"] += 70 debts["Vic"] -= 30 print "Vic paid 30 dollars, but still owes", debts["Vic"]
C 風格陣列(表現得像編號列表)和關聯陣列(表現得像字典)之間存在一些差異
| C 風格陣列 | 關聯陣列 |
|---|---|
|
|
Awk 只有關聯陣列,沒有 C 風格陣列。這種比較只針對那些從其他程式語言學習陣列的人。
讓我們回顧一下 Awk 陣列的一些更具體的特徵
Awk 中的陣列可以在程式執行過程中增長和縮小。每當訪問 Awk 之前從未見過的索引時,新條目會自動建立。無需讓 Awk 知道您打算使用多少個元素。
message[1]="Have a nice" message[2]="day." print message[1], message[2], message[3]
在這個例子中,陣列 message 中的元素 1 和 2 在我們為它們分配值的那一刻就被建立。在最後一行,訪問 message[3],儘管它還沒有建立。Awk 將建立元素 message[3] 並將其初始化為空字串(因此什麼都不會出現)。
此外,可以從陣列中刪除元素。以下是上述示例的擴充套件
delete message[2] message[3]="night." print message[1], message[2], message[3]
現在,message[2] 不再存在。就好像您從未在第一次為它賦值一樣,因此 Awk 將對它的提及視為空字串。如果您一起執行這兩個示例,結果將是
Have a nice day. Have a nice night.
(注意 print 語句中的逗號如何在陣列元素之間新增空格。這可以透過設定內建變數 OFS 來更改。)
一些實現,比如 gawk 或 mawk,也允許程式設計師刪除整個陣列而不是單個元素。在
delete message
之後,陣列 message 不再存在。
您已經看到 Awk 陣列使用字串來選擇陣列中的每個元素,就像字典一樣。
translate["table"] = "mesa" translate["chair"] = "silla" translate["good"] = "bueno"
但是,數字是完全可以接受的。像往常一樣,Awk 只會在需要時將數字轉換為字串。
translate[1] = "uno" translate[5] = "cinco"
然而,當用小數訪問陣列時,事情可能會變得棘手。
problems[ (1/3) ] = "one third"
您可以使用 problems[0.333] 訪問此元素嗎?不。這取決於內建變數 OFMT 的內容,它告訴 Awk 如何將數字轉換為字串。將轉換一定數量的小數位數,其餘的將被丟棄。一般來說,儘量避免使用帶小數的索引,除非您非常小心地使用正確的格式(可以更改)。
Awk 陣列是稀疏的,這意味著您可以有元素 1 和元素 3 而沒有元素 2。這很明顯——Awk 使用字串索引,因此它不區分編號元素。
更重要的是,關聯陣列中的元素不會按任何特定順序儲存。
有兩個有用的命令允許您檢查陣列中的元素。我們將在接下來的章節中詳細瞭解它們,但現在讓我們看一些示例。
if( "Kane" in debts )
print "Kane owes", debts["Kane"]
for( person in debts )
print person, "owes", debts[person]
回到介紹(其中建立了一個 debts 陣列將人們的姓名與金額相關聯),我們可以看到 Awk 提供了一些有用的命令來訪問陣列。第一個命令,if in,讓我們檢查特定元素是否已定義,然後根據該結果執行程式碼。第二個命令,for in,讓我們建立一個臨時變數(在本例中稱為 person),並在陣列中的每個元素上重複一條語句。
玩弄這些例子,看看 Awk 如何不一定會在其陣列中保持特定的順序。幸運的是,這從來都不是真正的問題。
Awk 陣列僅為單維。這意味著只有一個索引。但是,有一個名為 SUBSEP 的內建變數,除非您更改它,否則它等於 "@"。如果您希望建立一個多維陣列,其中每個元素有兩個或多個索引,您可以用逗號隔開它們。
array["NY", "capital"] = "Albany" array["NY", "big city"] = "New York City" array["OR", "capital"] = "Salem" array["OR", "big city"] = "Portland"
這些程式碼行與以下程式碼完全相同
array["NY@capital"] = "Albany" array["NY@big city"] = "New York City" array["OR@capital"] = "Salem" array["OR@big city"] = "Portland"
這只是多維陣列的快速演示。如您所見,這些實際上不是多維的;而是單維的,但使用特殊的分隔符。此處不會進一步探討多維陣列,因為必須理解幾個技術細節。您仍然可以在沒有它們的情況下編寫有用的 Awk 程式,但如果您對多維陣列感興趣,請隨時查閱您的 Awk 手冊(或者只是玩弄一下看看什麼有效)。
標準 Awk 中沒有用於陣列的函式。但是,gawk 提供了三個函式(A 和 B 應該都是陣列)
- length(A) 返回 A 的長度。
- asort(A[,B]) - 如果未給出 B,則對 A 進行排序。A 的索引將被替換為從 1 開始的連續整數。如果給出 B,則將 A 複製到 B,然後按上述方式對 B 進行排序,而 A 保持不變。返回 A 的長度。
- asorti(A[,B]) - 如果未給出 B,則丟棄 A 的值並對它的索引進行排序。排序後的索引將成為新的值,從 1 開始的連續整數將成為新的索引。與前一種情況類似,如果給出 B,則將 A 複製到 B,然後按上述方式對 B 的索引進行排序,而 A 保持不變。返回 A 的長度。
- 更新我們在本書開頭編寫的“coins”程式。使用陣列來統計按國家分類的硬幣數量。顯示結果以及摘要。
- 編寫債務人程式。它應該掃描一個日誌檔案,該檔案列出了像“Jim owes 50”和“Kim paid 30”這樣的交易。使用關聯陣列,對人們借入和償還的所有錢進行彙總。確保一個人可以在檔案中多次出現,並且他們的債務會得到相應的更新。在
END處,列出每個人及其總額。 - 改進#2中的程式,如果一個人償還了所有欠款,則從陣列中刪除他們的姓名。這樣,結果就不會被欠零元的人弄得亂七八糟。
下一頁快速回顧了 Awk 提供的所有運算子。