理系学生日記

おまえはいつまで学生気分なのか

awk でシェル変数の値を使うには

あたりまえだが、awk はシェル変数を参照できない。例えば以下のコマンドラインは 5 を出力せず、空行を出力する。

|tcsh| $ VAR=5 awk 'END { print VAR }' /dev/null ||<

一行だけを見ると、あぁそうなのかというくらいの話なのだけど、よく詰まるのがシェルスクリプト。例えばこれは以前に作ったものでターミナルからバッテリ情報を取得するスクリプトだけれど、ここで 98% 以上のバッテリが残っていれば "[CHARGED]" を出力させたいとする。

|tcsh| ioreg -n AppleSmartBattery | \ awk '/MaxCapacity/ { MAX=$5 } /CurrentCapacity/ { CURRENT=$5 } /InstantTimeToEmpty/ { REMAIN=$5 } END { printf("Battery: cur: %4d [mAh] max: %4d [mAh] (%5.2f%%) remain: %3d [min] \n", CURRENT, MAX, CURRENT/MAX*100, REMAIN) }' ||<

シェルスクリプト中でこのように書いても動作しない。CHARGE_THRESHOLD シェル変数は、awk の中からは見えないからだ。

|tcsh| CHARGE_THRESHOLD=98

ioreg -n AppleSmartBattery | \ awk '/MaxCapacity/ { MAX=$5 } /CurrentCapacity/ { CURRENT=$5 } /InstantTimeToEmpty/ { REMAIN=$5 } END { if ( CURRENT/MAX >= CHARGE_THRESHOLD ) { print "[CHARGED]" } }' ||<

THRESHOLD の値を awk の中で使うには、-v オプションを使う。

|tcsh| ioreg -n AppleSmartBattery | \ awk -v THRESHOLD=$CHARGE_THRESHOLD \ '/MaxCapacity/ { MAX=$5 } /CurrentCapacity/ { CURRENT=$5 } /InstantTimeToEmpty/ { REMAIN=$5 } END { if ( CURRENT/MAX >= CHARGE_THRESHOLD ) { print "[CHARGED]" } }' ||< で今の最終形はこんな感じにしてる。 |tcsh| ioreg -n AppleSmartBattery | \ awk -v THRESHOLD=${CHARGE_THRESHOLD:=98} \ '/MaxCapacity/ { MAX=$5 } /CurrentCapacity/ { CURRENT=$5 } /InstantTimeToEmpty/ { REMAIN=$5 } END { ORS=""; printf("Battery: cur: %4d [mAh] max: %4d [mAh] (%5.2f%%) ", CURRENT, MAX, CURRENT/MAX100); if (CURRENT/MAX100 > THRESHOLD) { print "[CHARGED]" } else { printf("[remain: %d (min)]", REMAIN); } print "\n";}' ||<