近日學到的幾個 awk 用法

傳遞環境變數到 awk script 裡

之前傻傻的以為在 awk script 裡用 ${var} 就可以使用環境變數,但實測結果是不行的,後來才找到 Can we use shell variable in awk?

使用方法很簡單,執行 awk 時用 -v var=${env_var} ,在 awk script 裡就可以使用 var 變數來取得環境變數。

echo "" | awk -v HOME=${HOME} '{print HOME}'

找出指定欄位符合條件的列

想找出其中一欄符合條件的所有列,又不想用 grep,找到這篇 Using awk with column value conditions 跟這篇 AWK 判斷有符合的 字串 或 條件 再印出資料,就直接用指定欄位的變數來判斷就可以,例如 $1

awk '$1 == "findtext" {print $0}' input.txt

忽略註解

下面範例是忽略註解,計算行數的,從 AWK: is there some flag to ignore comments? 看來的

awk '/^[[:space:]]*#/ { NR-- } {sum+=$3} END { ... }' coriolis_data
awk '{ if ($0 ~ /^[[:space:]]*#/) {NR--} else {sum+=$3} END { ... }' coriolis_data

awk 一行下載

為了下載投影片,但懶得一個個複製貼上、改指令,所以預先把投影片網址跟預定的檔名放在文字檔裡,然後用 awk 一次下載。

文字檔的格式是:url filename ,假定這個文字檔的檔名是 slides.txt

那麼,這樣就能搞定:

awk '{system("wget -O \"" $2 "\" " $1)}' slides.txt

參考資料:bash – awk system call – Stack Overflow

AWK 習作:關於 Android 的 mmssms.db

要把 mmssms.db 裡所有是 vCard 的記錄的檔案都下載到本地端。

主要會用到的資料表格是 part,會應用到的欄位是 ct 跟 _data,所以 SQL select 可以這樣寫:select _data from part where ct=’text/x-vcard’ COLLATE NOCASE

這裡為了不判斷大小寫,加上了 COLLATE NOCASE

為了在 terminal 下直接下指令,所以就變成 sqlite3 mmssms.db “select _data from part where ct=’text/x-vcard’ COLLATE NOCASE”

接著再應用 awk 與 adb:sqlite3 mmssms.db “select _data from part where ct=’text/x-vcard’ COLLATE NOCASE” | awk -F’\n’ ‘{system(“adb pull \”” $1 “\””);}’

這樣就大功告成了,-F’\n’ 是為了要把整行當作一個欄位,system() 函式是執行指令,awk 裡的字串串加,不需要特別加上 ‘+’ 或 ‘.’ ,直接寫,像這樣 “hello” $1 “world” 就可以了。

參考資料:

awk 的 pipe

之前都很笨,用 awk 處理完,還是都先用 printf 輸出到檔案,再用 sh 去執行。今天終於去查了 awk script 裡是否有類似 system() 的用法,果然 awk manual 裡就有提到 system() ,不過該小節建議了更好的做法,就是直接用 | 把輸出的指令 pipe 到 sh 去。

作法大致是這樣:

awk '{printf("cp %s /media/usbdisk%s\n", $1, $1) | "/bin/sh" }' files-list.txt