awk 命令
awk 簡述
awk [選項] '程式' file ...
| 
 | 設定欄位分隔字元,預設為「空白字元」或製表字元 (Tab 鍵)。 | 
| 
 | 將變數 var 設定成 value。 | 
- 記錄和欄位
- 
AWK 可以處理文字檔案和串流 (管道),輸入資料分為「記錄」和「欄位」。awk 一次對一條「記錄」進行操作,直到結尾 (EOF)。 
 「記錄」由「記錄分隔字元RS(Record Separator)」來分隔,預設的RS是換行字元,表示文字資料中的每一行都是一條記錄,可以使用變數設定不同的RS。
 一行記錄可由「欄位分隔字元FS(Field Separator)」分隔出不同欄位,預設的FS是空格或製表字元 (Tab 鍵),可採用命令列選項-F或變數設定不同的FS。每個欄位可由欄位變數 ($) 取得 $1 $2 $3 依此類推,$0 為全部內容,最後一個欄位也可以使用變數$NF。FS(欄位分隔字元) 設定為:,將/etc/passwd檔案標示出欄位如下:$grep ubuntu /etc/passwd ubuntu:x:1000:1000::/home/ubuntu:/bin/bash $1 :$2 :$4 :$6 :$7($NF) :$3 :$5 $0----------------------------------------
awk 程式 (program)
- 「程式 (program)」是由一系列模式動作對組寫成:
- 
'pattern {action}'其中 pattern(模式) 表示在資料中找出符合的「記錄(行)」,可為邏輯判斷式或正規表示式 (Regex),當省略pattern時,表示匹配所有記錄(行)。
 而{action}是在匹配記錄時所執行的動作,由大括號{}中的語句 (statement) 組成,{action}也可省略,省略時預設動作是列印該行的全部內容 (print $0)。
 語句 (statement) 可以解讀為「指令」。一個動作 (action) 有多個指令 (語句) 時,要寫在下一行或以分號 (;) 分開,如下:awk -F: ' { print $1 print $6 }' /etc/passwdawk -F: '{print $1; print $6}' /etc/passwd另外在「控制語句」 (如if) 中,如果有多個指令也需要由大括號{}組成複合語句,如下:awk -F: ' { if ($3 >= 1000) { print $1 print $3 } }' /etc/passwd
awk 模式 (pattern)
- 模式 (pattern) 判斷式
- 
邏輯判斷語法 x == y相等 x != y不相等 x > y大於 x >= y大於或等於 x < y小於 x <= y小於或等於 正規表示式語法 /Regex/匹配 Regex 表示式,表示式必須以定界字元 /包圍。!/Regex/否定匹配 Regex 表示式。 x ~ yx 匹配 y 正規表示式。 x !~ yx 不匹配 y 正規表示式。 AND OR 語法,適用邏輯判斷式及正規表示式。 &&AND 條件 ||OR 條件 以邏輯判斷式,列出UID大於或等於 1000 的帳戶awk -F: '($3 >= 1000) {print $1, $6}' /etc/passwd列出用戶名及家目錄為第 1 個欄位及第 6 個欄位 {print $1, $6},欄位變數之間的逗號 (,) 是列印欄位分隔字元OFS(Output field separator) 預設為空白字元。如果是{print $1 $6}並不會把欄位分隔,可採用" "字串,在字串中加入空格,如{print $1 " " $6}。以控制語句,列出UID大於或等於 1000 的帳戶awk -F: '{if ($3 >= 1000) print $1 " " $6}' /etc/passwd以正規表示式 (Regex) 匹配模式 (pattern),過濾具有家目錄的帳戶awk -F: '/\/home/ {print $1, $6}' /etc/passwd將記錄中整行的內容匹配模式 /\/home/,正規表示式必須以定界字元/包圍,而字元/必須以跳脫字元\轉譯成\/,內容匹配/home才會列印。匹配 (~) 兩個運算,$6 ~ /\/home/為欄位 6 匹配/home,本例的結果跟上面是一樣,只是上面是不區分欄位。awk -F: '$6 ~ /\/home/ {print $1, $6}' /etc/passwd- 以模式指定記錄範圍
- 
pattern1, pattern2 採用逗號 ( ,) 區分兩個位置;位置範圍由第一個位置pattern1至 (,) 第二個位置pattern2, 第二個開始匹配是在第一個位置或之後,記錄範圍始終跨越至少一個記錄 (行)。列印記錄內容 2 至 3 的記錄seq 5 | awk '$0==2, $0==3' seq 5 | awk '/2/, /3/'可混合「邏輯判斷式」及「正規表示式」seq 5 | awk '$0==2, /3/'列印記錄內容 3 至 2,由於第二個位置不合乎條件,將列印第一個位置記錄 (3) 至最後記錄 (5)seq 5 | awk '/3/, /2/'列印記錄內容 2 或 3 或 Yes 的記錄echo Yes | awk '/2/ || /3/ || /Yes/'在範圍模式中,逗號 (,) 是所有運算子中最低的優先權 (即;最後判斷)。因此,範圍模式與另一個運算結合起來:echo Yes | awk '/2/,/3/ || /Yes/'程式的意圖是(/1/,/2/) || /Yes/,但 awk 將其解讀為/1/, (/2/ || /Yes/),這無法改變或解決;範圍模式不能與其他模式結合:$echo Yes | awk '(/1/,/2/) || /Yes/' awk: cmd. line:1: (/1/,/2/) || /Yes/ awk: cmd. line:1: ^ syntax error 採用「控制語句」來處理:echo Yes | awk '{if ( ($0>=2 && $0<=3) || ($0=="Yes") ) print}'
 
- 多條模式 (pattern)
- 
在程式中可以有多條模式,合乎模式的以不同動作來處理。 awk -F: ' $1=="root" { print "The superuser is on line ", NR } $1=="www-data" { print "The user for the web server is on line ", NR } ' /etc/passwd
- BEGIN 和 END 特殊模式 (pattern)
- 
BEGIN { 尚未讀取前先執行的動作 } BEGINFILE { 檔案尚未讀取的動作 } { 讀取時執行的動作 } ENDFILE { 檔案讀取後執行的動作 } END { 讀取完成後執行的動作 }當程式 (program) 只有 BEGIN時,並不需要讀取檔案或管道輸入。
 在執行BEGIN時並未開啟及讀取檔案,BEGINFILE為開啟檔案,尚未讀取,再執行讀取時執行的動作,檔案讀取完成後執行ENDFILE,所有檔案處理完畢後最後執行END。當傳入多個檔案時,處理檔案按順序 (先開啟左邊的檔案) 把多個檔案當成接續的 (一個) 檔案,其行號 NR為接續。awk ' BEGIN { print "BEGIN FILENAME is", FILENAME } BEGINFILE { print "BEGINFILE", FILENAME, NR } { if (LastFileName != FILENAME) { LastFileName = FILENAME print "Read file", FILENAME, NR } } ENDFILE { print "ENDFILE", FILENAME, NR } END { print "END FILENAME is", FILENAME } ' /etc/passwd /etc/groupBEGIN FILENAME is (1) BEGINFILE /etc/passwd 0 (2) Read file /etc/passwd 1 (3) ENDFILE /etc/passwd 27 (4) BEGINFILE /etc/group 27 Read file /etc/group 28 ENDFILE /etc/group 81 END FILENAME is /etc/group (5) 1 BEGIN未開啟及讀取檔案2 BEGINFILE開啟檔案,尚未讀取檔案。3 執行「讀取時的動作」讀取檔案。 4 ENDFILE檔案讀取完成。5 END所有檔案處理完畢。
awk 變數
- 內建變數
- 
ARGC 命令列輸入參數數量 ARGV 命令列輸入參數內容 (陣列) NR (目前) 記錄位置 (行數)。 NF (目前) 記錄中欄位數。 FILENAME 檔案名稱。 FS (輸入的) 欄位分隔字元 (Field Separator),預設為「空白字元」或製表字元 (Tab 鍵)。 RS (輸入的) 記錄分隔字元 (Record Separator),預設為換行字元。 OFS 輸出欄位分隔字元 (Output Field Separator),預設值為空白字元。 ORS 輸出記錄分隔字元 (Output Record Separator),預設值為換行字元。 OFMT 輸出數字格式 (Format for numeric output),預設值為 %.6g。IGNORECASE 匹配或排序時不區分大小寫,預設值為 1。 RSTART 字串函數 match 專用,回傳匹配的 (開始) 位置。 RLENGTH 字串函數 match 專用,回傳匹配的 (內容) 長度。 SUBSEP (多主鍵) 陣列分隔字元。 FPAT 匹配 FPAT正規表示法,以匹配內容建立欄位,預設為[^[:space:]]+(不為空格的多個字元)。
 在程式中同時設定變數FS、FPAT,是以最後設定哪個變數來解析欄位,未設定變數預設是以FS來分隔。CSV是以逗號,來區分欄位,但字串中也會有逗號的情況如1,"2,b",3,這時只能用FPAT = "[^,]+|\"[^\"]+\""來處理。上述的正規表示法的意思是- 
匹配不為逗號 [^,]多個 (+) 字元
- 
或 |
- 
前後為雙引號 \"中間不為雙引號[^\"]多個 (+) 字元
 列印具有家目錄的帳戶及行數$awk -F: '/\/home/ {print $1,NR}' /etc/passwd syslog 21 ubuntu 24以BEGIN在讀取前先設定FS(輸入) 欄位分隔字元為:,OFS輸出欄位分隔字元為,:awk 'BEGIN {FS=":"; OFS=","} /\/home/ {print $1,NR}' /etc/passwd以命令列選項-v設定內建變數awk -vFS=: -vOFS=, '/\/home/ {print $1,NR}' /etc/passwd設定OFMT輸出數字格式示例awk 'BEGIN{OFMT="%.0f"; print 2.5, 3.5, 4.5, 5.5}'2 4 4 6 awk 的浮點進位為銀行進位法 (Banker’s Rounding) 可簡記為「四捨六入五成雙」,五成雙,尾數「5」的前一位,若雙數則為雙數,若為單數則進位。 
 如格式化字串為%.0f,參數輸入2.5, 3.5, 4.5, 5.5則輸出2, 4, 4, 6。
- 
- 自定變數
- 
awk 自定變數可為任意型別,如數字、浮點、字串或陣列。變數名稱不可跟函數名稱相同,如 index = 1(index 剛好為函數),由於變數區分大小寫,可以改名為Index = 1。變數內容指定為 16 進制數值,則內容值前置 0x,如myVar = 0x10(10 進制為 16),x或數值a至f不區分為大小寫可混用。
 8 進制則為前置0如myVar = 010(10 進制為 8)。
num=123
awk -v n=$num 'BEGIN {print n}'awk 控制語句
{action} 控制語句語法if (conditional)
  then-body-statement
else if (conditional)
  else-if-then-body-statement
else
  else-body-statement
initialization-statement
while (conditional) {
  body-statement
  increment-statement
  break
  continue
}
for (initialization; condition; increment)
  body-statement
  break
  continue
for (variable in array)
  body-statement
  break
  continue
switch (expression) {
case value or regular_expression:
  case-body-statement
  break
default:
  default-body-statement
  break
}
next
exit [return_code]
nextfile- next
- 
處理下一筆記錄,若不為 EOF重啟循環,回到「讀取時執行的動作」程式開始位置 (不會執行next後面的程式)。
awk 函數
print 內的逗號 , 是列印 OFS 欄位分隔字元,數字輸出格式為 OFMT (預設為 %.6g),執行 print 後會加印 ORS 輸出記錄分隔字元 (預設為換行字元)。可設定內建變數 OFS、OFMT 及 ORS 改變預設行為。print $1 $2 並不會把欄位分隔,可採用 " " 字串,在字串中加入空格,如 print $1 " " $2。
print 無參數時為 print $0,另外在 awk 程式 (program) 的 pattern {action},當省略 {action} 時預設動作也是 print $0。
printf
printf format [, argument-list]format (格式) 為字串,argument-list 是對應於 format 的參數列表。
% [parameter] [flags] [width] [.precision] type
| parameter (參數) | |
| N$ | 列印第 N 個參數,如  | 
| flags (修飾字元) | |
| 
 | 左對齊,不足寬度時在右邊填滿空格,如  | 
| 
 | 用於數字;在正數前面增加一個  | 
| space | 用於數字;在正數前面增加一個空格 (space),主要是用於跟負數對齊。如  | 
| 
 | 用於數字;不足寬度時在左邊填滿  | 
| 
 | 用於數字;加上千位分隔符號;支援千位分隔表示的  由於  '(單引號) 需要轉譯,以 16 進制\x27避開。以下列示處理'(單引號) 的方式: | 
| 
 | 類型 (type)  為  | 
| width (寬度) | |
| 「寬度」指定輸出的最少字元數,通常用於固定寬度的輸出。 「寬度」可以省略,或者當作為另一個參數傳遞時由星號  | |
| precision (精度) | |
| 「精度」通常指定輸出的最多字元數,在不同 type (類型) 其義意不同: 
 「精度」可以省略,或者當作為另一個參數傳遞時由星號  | |
| type (類型) | |
| 
 | 字元,參數為數字如  | 
| 
 | 整數,無條件捨去法。 | 
| 
 | 以科學記號顯示浮點數,小寫  | 
| 
 | 浮點數值格式化成定點 (fixed-point)。 | 
| 
 | 通用浮點型,自動顯示成「浮點 (定點) 類型」或「科學記號類型」,整數位數已經超過由「精度」指定的有效位數,則會顯示成科學記號。小寫  | 
| 
 | 8 進制。 | 
| 
 | 字串。 | 
| 
 | 16 進制, | 
| 
 | 輸出一個  | 
| 
 | Alert (警報) 嗶聲 (beep), Ctrl+g,ASCII code 7 (BEL). | 
| 
 | 倒退键 Ctrl+h,ASCII code 8 (BS). | 
| 
 | 製表字元,Tab、Ctrl+i,ASCII code 9 (HT). | 
| 
 | 換行字元,Ctrl+j,ASCII code 10 (LF). | 
| 
 | 垂直製表字元,Ctrl+k,ASCII code 11 (VT). | 
| 
 | 換頁字元,Ctrl+l,ASCII code 12 (FF). | 
| 
 | 確認鍵,Ctrl+m,ASCII code 13 (CR). | 
| 
 | 8 進制值 nnn,其中 nnn 為  | 
| 
 | 16 進制數值 hh( | 
| 
 | 輸出一個  | 
| 
 | 在字串中輸出  | 
數學函數
| 
 | x 除以 y 的餘數。 | 
| 
 | x 的 y 次方 | 
| 
 | 正弦 | 
| 
 | 餘弦 | 
| 
 | 反正切 | 
| 
 | 指數 | 
| 
 | 對數 | 
| 
 | 開根號 | 
| 
 | 整數值 (無條件捨去小數) | 
| 
 | 初始化亂數  | 
| 
 | 回傳亂數 n,0 <= n < 1。 | 
位元操作函數
| 
 | |
| 回傳位元運算  | |
| 
 | |
| 回傳  val 位元運算的補數 (complement),將  | |
| 
 | |
| 回傳 val 以位元 (bit) 左移 count 位,(左邊) 高位拋棄,(右邊) 低位補 0。 | |
| 
 | |
| 回傳位元運算  | |
| 
 | |
| 回傳 val 以位元 (bit) 右移 count 位,(左邊) 高位補 0,(右邊) 低位拋棄。 | |
| 
 | |
| 回傳位元運算  | |
字串函數
| 
 | |
| 將 source 的「內容值」排序。排序後的陣列主鍵由整數 1 開始,陣列內容為「內容值」。如果有指定 dest 則排序結果會儲存在 dest (source 不變)。內建變數  | |
| 
 | |
| 將 source 的「主鍵值」排序,排序後的陣列主鍵由整數 1 開始,陣列內容為「主鍵值」。如果有指定 dest 則排序結果會儲存在 dest (source 不變)。內建變數  | |
| 
 | |
| 將輸入的 source 匹配 regexp 替換為 replacement 回傳替換後的文字。
未指定 source 參數其來源為欄位 $0,how 設定為數字 n 表示第 n 次開始替換,若為  | |
| 
 | |
| 回傳字串 find 在 in 的位置 (不支援正規表示法)。 | |
| 
 | |
| 回傳字串長度,如果沒有 string 參數則回傳  | |
| 
 | |
| 取得 string 匹配 regexp 的位置和長度,將開始位置填入內建變數  array 為正規表示法中分組功能的回撥  | |
| 
 | |
| 字串 string 匹配 fieldpat 模式,將合乎模式匹配的文字建立陣列 array,如省略 fieldpat 預設為內建變數  | |
| 
 | |
| 字串 string 分割後 (的前後) 建立陣列 array,如省略 fieldsep 預設為內建變數  | |
| 
 | |
| 回傳(不列印)printf (使用相同參數) 輸出的字串。 | |
| 
 | |
| 將 str 轉成數字 (含小數),若 str 前置  | |
| 
 | |
| 將 target 匹配 regexp 替換一次成為 replacement,替換後的文字取代 target。沒有指定 target 參數時預設為欄位變數  | |
| 
 | |
| gsub 跟 sub 類似,sub 只替換一次,gsub 為全部替換。 | |
| 
 | |
| 回傳字串 string 開始位置 start 長度 length,沒有指定 length 則至 string 的結尾。 | |
| 
 | |
| 轉成小寫 | |
| 
 | |
| 轉成大寫 | |
輸入輸出函數
| 
 | |
| 輸入的檔案或管道,在經過讀取後,其讀取的位置會增加,如果不關閉輸入,則後續的讀取是接續上次的位置。 在雙向管道 (two-way pipe) 或稱為 coprocess (協助) 可以指定 how 參數, 若  | |
| 
 | |
| 將輸出檔案或管道的緩衝區排清 (flush) 確定已寫入。  | |
| 
 | |
| 執行操作系統的命令 command 回傳命令的狀態碼。 | |
| 
 | |
| 讀取下一筆記錄儲存至 target 並回傳讀取狀態,沒有指定 target 時將儲存至  執行  getline錯誤時並不會出錯,而是回傳狀態:
 採用  
 | |
getent hosts 8.8.8.88.8.8.8 dns.google
getline 取得 IP 位置的名稱echo -e '8.8.8.8\n8.8.4.4' | awk '
{
  "getent hosts " $0 | getline Hosts;
  split(Hosts, Hosts_Arr, " ");
  print $0, Hosts_Arr[2]
}'8.8.8.8 dns.google 8.8.4.4 dns.google
awk  -F: '
{
  User = $1
  UID = $3
  while ( (getline < "/etc/group") > 0 )
  {
    if (User ==  $1) {
      print $1, UID, $3
      break
    }
  }
  close("/etc/group") (1)
}' /etc/passwd| 1 | 關閉檔案後,第二次才能從頭開始讀取。 | 
註:本例是為了說明 close,並未最佳化,在 BEGIN{} 時先將 /etc/group 全部讀取至陣列再以陣列查表,比較理想。
- print printf 重定向輸出
- 
print及printf的管道輸出字元其運作跟管道一樣。print > "filename" print >> "filename" print | "command" print |& "command_coprocess" - 將輸出檔案錯誤視為非嚴重錯誤
- 
當 PROCINFO["NONFATAL"]或者PROCINFO["filename", "NONFATAL"]存在時 (不管項目設定值,設為 0 也一樣),則print重定向至檔案的 I/O 錯誤將變為非嚴重錯誤 (註:awk 5.0 才會作用)。awk ' BEGIN { PROCINFO["/no/such/file", "NONFATAL"] = 0 (1) ERRNO = 0 print "hi" > "/no/such/file" if (ERRNO) { print("Output failed:", ERRNO) > "/dev/stderr" exit 1 } }'1 設定為 0 是在解釋該項目存在時即有作用,實際上不需要設定;或者設定為 1。 Output failed: No such file or directory 
 
- 雙向管道
- 
將管道的輸入及輸出;由 print傳送給命令的「管道輸入」;由getline讀取命令的「管道輸出」。以|&建立雙向管道print |& command command |& getline x|跟|&可能混淆以為行為一樣,| command是由命令直接輸出,而|& command其命令是回傳給 awk,命令並不會輸出。依據命令的特性,如命令是以逐行來處理,則每傳送一筆記錄後執行 close(command, "to")在管道中寫入EOF,避免要求讀取所有資料後才會處理的「命令」發生阻塞 (永久等待)。
 傳送後執行關閉管道的輸出close(command, "to"),在執行getline之後也需要執行close(command),這兩個close是成對的。{ print |& command close(command, "to") (1) if ( (command |& getline x) > 0 ) print x close(command) (2) }1 close(command, "to")在管道中寫入EOF。2 在處理後需要執行 close(command),這兩個close是成對的。如果命令是讀取所有的輸入後才處理 (或者是讀取全部後才會正確),那麼則分段;先傳送所有記錄後,再傳送 EOF,再以getline(全部) 讀取。{ print |& command (1) } END { close(command, "to") (2) while ( (command |& getline x) > 0) { print x } close(command) (3) }1 先傳送所有記錄。 2 傳送所有記錄後,再傳送 EOF。3 實際上並不需要該指令,但加入該指定比較合乎 close的用法。將使用者帳戶轉成大寫 (逐行處理)awk -F: ' BEGIN { command="awk \x27{ print toupper($0) }\x27" (1) } { print $1 |& command close(command, "to") if ( (command |& getline x) > 0 ) print x close(command) } ' /etc/passwd1 command即為awk '{ print toupper($0) }',將 ' (單引號) 以 16 進制\x27避開轉譯。將使用者帳戶經過cat -n加上行號,讀取後再列印 (全部資料分段處理)。awk -F: ' BEGIN { command="cat -n" } { print $1 |& command } END { close(command, "to") while ( (command |& getline x) > 0 ) print x close(command) } ' /etc/passwd
awk '
BEGIN {
  command = "echo hi"
  print "getline return:" (command | getline)
  print "close return:" close(command)
  print "----------"
  command = "sleep 1 && echo hi"
  PROCINFO[command, "RETRY"] = 1
  PROCINFO[command, "READ_TIMEOUT"] = 200
  print "getline return:" (command | getline), "ERRNO:" ERRNO
  print "close return:" close(command), "ERRNO:" ERRNO
  print "close return:" close(command), "ERRNO:" ERRNO
}'getline return:1 close return:0 ---------- getline return:-2 ERRNO:Connection timed out (1) close return:269 ERRNO: (2) close return:-1 ERRNO:close of redirection that was never opened
| 1 | 不一定是 -2,awk 4.1.4 為 -1。 | 
| 2 | 不一定是 269 可能是其他非 0 的數字。 | 
awk 關聯陣列
陣列主鍵值為唯一,陣列主鍵 (及內容值) 可為文字或數字,收集或統計欄位的情況。
- 陣列類型
- 
- 
array[x,y]多主鍵陣列
 水果有多種顏色,水果及顏色為同一組資料時,可採用多主鍵陣列。
- 
array[x][y]多維陣列
 水果有多種顏色,如要各別列出水果、顏色,處理不同的維度時,應採用多維陣列。
 多主鍵陣列是儲存在一維陣列,其主鍵是以SUBSEP(陣列分隔字元) 來分隔,該字元即為 Ctrl+\。awk ' BEGIN { a[1,1] = 11; a[1,2] = 12; a[2,2] = 22; for (i in a) print i } ' | cat -v2^\2 1^\1 1^\2 多維陣列,在程式中可取得一個維度,其數量為該維度的個數。awk ' BEGIN { a[1][1] = 11; a[1][2] = 12; a[2][2] = 22; for (x in a) { print x for (y in a[x]) print "\t" y } } '1 1 2 2 2
- 
cat > sales.txt << EOF
sales,fruit,color,qty,amount
john,apple,red,1,100
john,banana,yellow,2,200
john,kiwi,green,3,300
kevin,lemon,yellow,1,100
marry,banana,yellow,2,200
marry,apple,green,3,300
EOFawk -F, '
{
  if (NR < 2) next
  fruitAmount[$2] += $5
  salesAmount[$1] += $5
}
END {
  print "---------- Fruit amount"
  for (fruit in fruitAmount) print fruit, fruitAmount[fruit]
  print "---------- Sales amount"
  for (sales in salesAmount) print sales, salesAmount[sales]
}
' sales.txt- 
if (NR < 2) next目前行號 (NR) 小於 2 時,執行下一行next。
- 
fruitAmount[$2] += $5水果銷售陣列fruitAmount其主鍵為水果欄位$2,內容為累加銷售金額$5。
 寫成fruitAmount[$2] = fruitAmount[$2] + $5也相同。
- 
for (fruit in fruitAmount)由for取得fruitAmount的每個主鍵fruit(水果欄位)。
- 
fruitAmount[fruit]以主鍵fruit取得fruitAmount銷售金額內容值。
---------- Fruit amount apple 400 banana 400 lemon 100 kiwi 300 ---------- Sales amount kevin 100 marry 500 john 600
- 預先定義的陣列排序
- 
陣列排序@[ind|val]_[num|type|str]_[asc|desc]選項- 
@unsorted無排序。
- 
ind按主鍵(索引)排序,val按內容值排序。
- 
num嘗試以數字排序 (1a會以1排序),無前置數字在前。
 str按字串 (文字) 順序排序。
 type按類型排序,數字類型或類數字 (內容全部為數字) 在前,字串 (文字) 類型在後 (1a為字串類型)。
- 
asc為升冪,desc為降冪。
 陣列排序組合列表@ind_num_asc@ind_num_desc@ind_str_asc@ind_str_desc@val_num_asc@val_num_desc@val_str_asc@val_str_desc@val_type_asc@val_type_desc
 註:沒有ind_type的組合。使用方式PROCINFO["sorted_in"] = "@ind_str_asc" for (i in array) print i, array[i] strnumtype排序示例awk ' function sortdemo(format, arr) { PROCINFO["sorted_in"] = format (4) print format for (i in arr) { print typeof(arr[i]), arr[i] (5) } print "-------------" } BEGIN { split("31 5 red 1a", a) (1) a[100] = 400 (2) sortdemo("@val_str_asc", a) (3) sortdemo("@val_num_asc", a) sortdemo("@val_type_asc", a) } '1 建立陣列 a內容值為31、5、red、1a。2 陣列 a[100]設定為數字 400。3 將排序方式 @val_str_asc傳遞給sortdemo的 format。4 sortdemo設定排序方式 format。5 列印每個陣列的資料類型及內容 (awk 4.2 才有支援 typeof函數)。@val_str_asc string 1a strnum 31 number 400 strnum 5 string red ------------- @val_num_asc string red string 1a strnum 5 strnum 31 number 400 ------------- @val_type_asc strnum 5 strnum 31 number 400 string 1a string red ------------- 
- 
awk -F, '
{
  if (NR < 2) next
  fruitQty[$2,$3] += $4
  fruitAmount[$2,$3] += $5
}
END {
  PROCINFO["sorted_in"] = "@ind_str_asc"
  for (combKey in fruitQty) {
    split(combKey, sepKey, SUBSEP)
    print sepKey[1], sepKey[2], fruitQty[sepKey[1], sepKey[2]], fruitAmount[sepKey[1], sepKey[2]]
  }
}
' sales.txt- 
for (combKey in fruitQty)由for取得fruitQty的每個主鍵combKey。
- 
split(combKey, sepKey, SUBSEP)
 由於 (原始的)fruitQty為多主鍵,combKey也是多主鍵,執行split以SUBSEP(陣列分隔字元) 分割出每個主鍵儲存至陣列sepKey中的sepKey[1]、sepKey[2]。
- 
fruitQty[sepKey[1], sepKey[2]]以主鍵sepKey[1]、sepKey[2]取得fruitQty的內容值,fruitAmount的主鍵跟fruitQty相同,以相同的主鍵fruitAmount[sepKey[1], sepKey[2]]取得fruitAmount的內容值。
apple green 3 300 apple red 1 100 banana yellow 4 400 kiwi green 3 300 lemon yellow 1 100
asorti 示例)awk -F, '
{
  if (NR < 2) next
  fruitQty[$2,$3] += $4
  fruitAmount[$2,$3] += $5
}
END {
  asorti(fruitQty, sortKey)
  for (i=1; i in sortKey; i++) {
    split(sortKey[i], sepKey, SUBSEP)
    print sepKey[1], sepKey[2], fruitQty[sepKey[1], sepKey[2]], fruitAmount[sepKey[1], sepKey[2]]
  }
}
' sales.txt執行結果跟前述的「水果銷售明細結果」相同。
- 
asorti(fruitQty, sortKey)將fruitQty的主鍵排序後儲存至sortKey其主鍵值由整數 1 開始。sortKey陣列如下:1 apple^\green 2 apple^\red 3 banana^\yellow 4 kiwi^\green 5 lemon^\yellow 
- 
for (i=1; i in sortKey; i++)由for取得每個整數主鍵i。for的 condition 為i in sortKey改為i <= length(sortKey)也相同。for (i=1; i <= length(sortKey); i++) 
- 
split(sortKey[i], sepKey, SUBSEP)
 sortKey[i]為 (已排序的) 多主鍵的內容,執行split以SUBSEP(陣列分隔字元) 分割出每個主鍵儲存至陣列sepKey中的sepKey[1]、sepKey[2]。
- 
fruitQty[sepKey[1], sepKey[2]]以主鍵sepKey[1]、sepKey[2]取得fruitQty的內容值,fruitAmount的主鍵跟fruitQty相同,以相同的主鍵fruitAmount[sepKey[1], sepKey[2]]取得fruitAmount的內容值。
awk -F, '
{
  if (NR < 2) next
  fruitSales[$2][$3]["qty"] += $4
  fruitSales[$2][$3]["amt"] += $5
}
END {
  PROCINFO["sorted_in"] = "@ind_str_asc"
  for (fruit in fruitSales) {
    subqty = 0; subamt = 0;
    for (color in fruitSales[fruit]) {
      qty = fruitSales[fruit][color]["qty"]
      amt = fruitSales[fruit][color]["amt"]
      print fruit, color, qty, amt
      subqty += qty; subamt += amt;
    }
    print "--------------------"
    print fruit, "subtotal", subqty, subamt
    print ""
  }
}
' sales.txtapple green 3 300 apple red 1 100 -------------------- apple subtotal 4 400 banana yellow 4 400 -------------------- banana subtotal 4 400 kiwi green 3 300 -------------------- kiwi subtotal 3 300 lemon yellow 1 100 -------------------- lemon subtotal 1 100
(
cat << EOF
fruit,color-list
apple,green,red
lemon,green,yellow
banana,yellow
kiwi,green,gold
grape,black,red,purple
EOF
) |
awk -F, '
{
  if (NR < 2) next
  for(i=2; i<=NF; i++)
    array[$i][$1]
}
END {
  PROCINFO["sorted_in"] = "@ind_str_asc"
  for (color in array) {
    print color, length(array[color])
    for (fruit in array[color]) {
      print "\t" fruit
    }
  }
}
'- 
for(i=2; i<=NF; i++)由for取得 i,該值跳過第 1 欄位的水果,由 2 開始至該行的欄位數NF,i 值為顏色欄位。
- 
array[$i][$1]收集多維陣列array第 1 維度的主鍵為顏色欄位$i,第 2 維度的主鍵為水果$1。
 註:只需收集主鍵值,不需要內容值。
black 1
        grape
gold 1
        kiwi
green 3
        apple
        kiwi
        lemon
purple 1
        grape
red 2
        apple
        grape
yellow 2
        banana
        lemon