理系学生日記

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

忍者TOOLS

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

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

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

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

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 の中からは見えないからだ。

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 オプションを使う。

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]" } }'

で今の最終形はこんな感じにしてる。

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/MAX*100);
            if (CURRENT/MAX*100 > THRESHOLD) {
                print "[CHARGED]" 
            }
            else { 
                printf("[remain: %d (min)]", REMAIN); 
            }
            print "\n";}'