Classic Shell Scripting 讀書筆記 (五)

  • Devops

AWK

  • 所有 UNIX 系統裡都至少有一套 awk
  • awk 是 POSIX 的一部分
  • 把輸入流看成一連串紀錄(record)的集合,每筆紀錄可以更進一步細分成字段(field)
  • 如何構成一筆紀錄和一個字段,是可控制的,甚至可以在處理期間修改
  • 替使用者妥善處理每個文件的開啟、讀取與關閉
  • 強大的功能大多是具備對正則表達式的支援

命令行

  • 慣例是將 -F 當作第一個選項,或者也可以設定變量 FS 來重新定義分隔符

    以上面例子來看,-F 應用到第一個文件組,而 FS 應用到第二個文件組

  • -- 是特殊選項,指出 awk 本身已經沒有更進一步的命令行選項

  • 初始化的 -v 必須放在 program 之前,在文件處理之前生效

  • program 使用單引號,保護內容不被 Shell 解釋,不過要特別注意程序是否本身包含單引號

程序元素

  • 提供標量(scalar)、陣列(array)兩種資料結構
  • 提供語句類型:賦值、註釋、條件、函數、輸入、循環、輸出

字串表達式

  • 以雙引號定界
  • 長度沒有任何限制,視內存而定
  • 賦值後舊字串的內存空間會自動回收
  • 字串的比較視字串長短而定,如 “A” < “AA” 返回 1
  • awk 無字串連接的運算符,多個連續的字串,會自動連接在一起
  • 數字轉字串,可透過連接空字串,如 s = “” + 123

正則匹配語句

  • 提供兩個運算符: ~!~ 分別代表匹配和不匹配
  • 正則常量可以用雙引號或斜槓 / 定界,斜槓形式比較常見,因為可以用來強調括起來的就是正則表達式
  • 字面意義的引號、斜槓、反斜槓在正則裡都應該被保護,兩種形式的保護方式可能不同,例如 "\\\\TeX"/\\Tex/ 都是表示正則的 \Tex

數值表達式

  • 所有 awk 裡的數字都以雙精確度的浮點值(對應於 C 的 double)表示
  • awk 在 IEEE 754 廣泛可用前就以開發,無法完整支持 Infinity 與 NaN
  • 浮點數可以包含一個末端以字母 e(或 E)所表示的十次方指數,例如 0.03125、3.125e-2、0.003125E1
  • 字串轉數字,可透過連接0,如 n = 0 + “123”

IEEE 754

  • 64 位雙精度的值包含 1 位正負號、11 位偏移指數,以及 53 位顯著位,表示最多可存 16 位的十進制數字 (2^53)
  • 值太大無法表示,會顯示 overflow 並回傳 Infinity
  • 值未正確定義,如 Infinity – Infinity 或 0 / 0 則結果是 NaN
  • 相同正負號的 Infinity 比較時是相等的,NaN 比較時則不等於它自己(假設 x 為 NaN,則 x != x)

數值運算符

  • 指數運算與賦值運算具有右結合性,如 a^b^c^d 意即 a^(b^(c^d))
  • ****= 運算符並不在 POSIX 標準內,請用 ^^= 取代
  • 支援三元條件式,如 a = (u>w)?x^3:y^7

標量變量(scalar)

  • 所有 awk 變量在建立時的初始值為空字串,但是當需要數值時,它會被視為 0
  • 命名規則:局部變量為小寫、全域變量第一個字母為大寫、內建量全為大寫

數組變量(array)

  • 以方括號將任意數字或字串作為索引,稱為關聯數組(key-value pair)
  • 儲存空間是稀疏的(sparse),聲明的元素才會被配置
  • delete array[index]delete array 回收空間,但數組名稱不會被刪除
  • 一個變量不能同時用作標量變量和數組變量
  • 不支持多維數組如 array[index1][index2],但支援多個索引如 array[index1, index2]
  • 針對逗號分隔的多個索引,awk 將其視為一個字串,以內建變量 SUBSEP 取代逗點,例如 array[index1, index2] 的索引會轉換成 index1 SEBSEP index2,預設的 SUBSEP 是 \034
  • 為了避免 SUBSEP 被修改,每個程序應該只在 BEGIN 操作裡設置一次

命令行參數

awk 透過內建變量 ARGC(參數計數) 與 ARGV(參數值),讓命令行參數變得可用,以下方範例說明:

須注意的是,program、與 -f 或 -v 選項結合的參數是不可使用的

環境變量

awk 提供內建數組 ENVIRON 來新增、修改及刪除環境變量,但此數組的變更無法傳遞給子進程,因此應該只做讀取使用(readonly)

分隔符

  • awk 以內建變量 RS 分隔紀錄(在 POSIX 中為單一字串,預設為換行),再以內建變量 FS (正則表達式,默認為空格)分隔字段

  • gawk、mawk 支援 RS 可以是正則表達式

  • FS 只有在超過一個字符時,才會被視為正則表達式,如不會視 FS = "." 為正則

  • 使用預設 FS 分隔字段時,連續的空格(如 tab)、及行的開頭及結尾的空白會被自動忽略,除非明確指定只匹配一個空格 FS = "[ ]"

字段

  • 字段可以透過特殊名稱 $1、$2、$NF 使用,此名稱會轉換成整數,如 $3.14 及 $(27/9) 都會引用到第三個字段
  • 不帶$號的 NF 變量代表一筆紀錄的字段數
  • 名稱 $0 引用到當前紀錄
  • 引用大於 NF 範圍以外的名稱會回傳空字串,引用小於 0 的負值字段編號則會噴錯

模式與操作

  • 可以使用逗號隔開的兩個表達式來選取範圍(range expression)
  • 在 BEGIN 區塊裡,引用 FILENAME、FNR、NF、NR 會回傳 NULL 或 0,因為初始值尚未定義
  • 在 END 區塊裡,FILENAME 是最後一個要處理的輸入文件,FNR、NF、NR 則會保留最後一筆輸入紀錄而來的值

以下這些模式/操作組合的結果是一樣的:

改變輸出的分隔符,至少須指定一個字段(即使沒有做任何變更):

常見單行操作

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。