AWK によるデータ処理(2)

目次 これから 出てくる awk プログラムは 長いものが 多く なります。 長い プログラムは ファイルに 作成して 実行しましょう。

AWK による計算

BEGIN と END を うまく 使うと、 欄の 合計 などの 計算を おこなう ことが できます。

数え上げ

次の プログラムは 15時間 以上 働いた 従業員を 数えるのに、 変数 emp を 使って います。
$3 > 15 { emp = emp + 1 }
END { print emp, "employees worked more than 15 hours." }
3つ目の 欄が 15を 越えるような 行を 読み込む たびに、 それまでの emp の 値を ひとつ 増やして います。 数値 として 使用される awk の 変数は、 最初に 値 0 から 始まります。 したがって、 emp を 初期化する 必要は ありません。
上の awk プログラムを m15.awk という名前で作成しておき、以下のように実行します。
sw%99 awk -f m15.awk emp.dat 
3 employees worked more than 15 hours.
以下、同様に awk プログラムファイルの作成と実行を練習して下さい。

和と平均の計算

従業員の 数を 数えるのに、 それまで 読み込んだ 行数が 入る 組み込み 変数 NR を 利用 できます。
    { pay = pay + $2 * $3 }
END { print NR, "employees";
      print "total pay is",pay;
      print "average pay is",pay/NR;
    }
という プログラムは、 賃金の 合計を pay に 加算して いきますから、 最後に、 従業員の 数と 合計賃金、 平均賃金を 表示する ことに なります。 一つのアクション内に複数の命令(式)を書くときは ; (セミコロン)で 区切ります。上の print の例では必ずしも必要ではありませんが、 習慣として入れておいた方がよいでしょう。

文章の操作

Awk では、 数値 だけでなく 文字列を 変数に いれる ことも できます。
$2 > max { max = $2; who = $1 }
END { print "Highest hourly rate:", max, "for", who }

文字列の連接

文字列を つなぎ 合わせて、 新しい 文字列を 作る ことも できます。 この 文字操作を 連接 と 呼びます。
    { names = names $1 " " }
END { print names }

最後の行の表示

組み込み 変数 NR は END の 実行時にも 値を 保持して いますが、 $0は そうでは ありません。 次の プログラムは 最後の 入力行 だけを 表示します。
    { last = $0 }
END { print last }

全部まとめて処理

上の処理をまとめて一つの awk ファイルに書くこともできます。
BEGIN { print "*** Employee Statistics ***" }

$3 > 15 { emp = emp + 1 }
    { pay = pay + $2 * $3 }
$2 > max { max = $2; who = $1 }
    { names = names $1 " " }
    { last = $0 }

END { 
      print "Employee list:", names;
      print NR, "employees";
      print emp, "employees worked more than 15 hours." ;
      print "total pay is",pay;
      print "average pay is",pay/NR;
      print "Highest hourly rate:", max, "for", who ;
      print "Who was the last:",last;
    }

入力区切り子の変更

Awk を 起動する 際に -F オプションを 使うか、 組み込み 変数 FS を 使うことで、 入力の 欄区切りを 表す 文字を 変更する ことが できます。 例えば、awk -F: ... や {FS = ":"} のように 指定すると 入力の 欄区切り子が : に 変わります。

システム固有のユーザ(root や lp など裏方の仕事をするようになっています) は /etc/passwd に定義されています。 このファイルでの 各項目は : で 区切られて いますから、

sw99%  awk -F: '$1 == "root" {print $5}' /etc/passwd
とすれば、 root さんの 本名が 出てきます。 ネットワーク情報システム NIS+ に登録されたユーザの場合は別のコマンドで ユーザ情報のリストを表示することができます。 (但し、 awk を 使わなくても、 finger コマンドを 使えば 本名や その他の 情報が 表示されます。)

以上のほかにも、 awk は 組み込み 関数や、 if-else文、 while文、 for文 などを 使った 複雑な 計算や プログラム制御を おこなう ことが できます。 これらの 詳細に ついては、 C言語を 学んだ 後で 参考書 「プログラミング言語AWK」 エイホ・ カーニハン・ ワインバーガー著・ 足立訳 (トッパン・ 3,400円) を 読むことを 勧めます。

練習問題

  1. すべての 入力行の 欄の 総数を 表示する には どうしたら よいで しょう? (ヒント: 欄の 数は NF に 入って います。)
  2. 最後の 行の 最後の 欄を 表示するには どうしたら よいでしょう?
  3. 前回の授業で作成した acc.dat から、分類が in の金額を合計して 表示しなさい。(変数名に in を使うと「予約語」のため エラーになります)
  4. acc.dat から 分類が eat, other の金額をそれぞれ合計して表示しなさい。
  5. acc.dat から、1週間の収支(手元に残った金額)を計算して表示しなさい。
上の問題の 3,4,5 を同時に行う awk プログラムを作成し、 授業担当者へメールで送信しなさい。(添付は使わず、コピー&ペースト してください。)

awk を使った難しい例題もあります。