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

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

AWK による計算

BEGIN 、END と、今回説明する変数を うまく 使うと、 欄の 合計 などの 計算を おこなう ことが できます。
今回も前回と同じ勤務時間表のデータを用います。前回欠席した人はこちらのファイルemp.datをクリックしてダウンロードしておいてください。
Beth    4.00    0
Dan     3.75    0 
Kathy   4.00    10 
Mark    5.00    20 
Mary    5.50    22
Susie   4.25    18

数え上げ

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

和と平均の計算

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

文章の操作

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


変数が文字列であるか、数値であるかは、
代入された値をもとに柔軟に判断してくれます。

文字列の連接

文字列を つなぎ 合わせて、 新しい 文字列を 作る ことも できます。 この 文字操作を 連接 と 呼びます。
m4.awk
    { names = names $1 " " }
END { print names }
 
sw99% awk -f m4.awk emp.dat
Beth Dan Kathy Mark Mary Susie 


最後の行の表示

組み込み 変数 NR は END の 実行時にも 値を 保持して いますが、 $0は そうでは ありません。 最後の行を表示するには、変数に行の内容を保存しておく必要があります。次の プログラムは 最後の 入力行 だけを 表示します。
m5.awk
    { last = $0 }
END { print last }
 
sw99%  awk -f m5.awk emp.dat 
Susie   4.25    18

全部まとめて処理

上の処理をまとめて一つの awk ファイルに書くこともできます。
m6.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;
    }

実行すると以下のようになります

 
sw99% awk -f m6.awk emp.dat
*** Employee Statistics ***
Employee list: Beth Dan Kathy Mark Mary Susie 
6 employees
3 employees worked more than 15 hours.
total pay is 337.5
average pay is 56.25
Highest hourly rate: 5.50 for Mary
Who was the last: Susie 4.25    18

入力区切り子の変更

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

システム固有のユーザはniscat passwd.org_dirで表示できます。 この出力の各項目は : で 区切られて いますから、

 
sw99%  niscat passwd.org_dir | awk -F: '$1 == "root" {print $5}' 
とすれば、 root さんの 本名が 出てきます。  (但し、 awk を 使わなくても、 finger コマンドを 使えば 本名や その他の 情報が 表示されます。)

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

課題

送付先 honda@is.kochi-u.ac.jp
提出期限 2017/2/2(木)17:00
タイトル   awk2

  1. すべての 入力行の 欄の 総数を 表示する には どうしたら よいで しょう? (ヒント: 欄の 数は NF に 入って います。)
  2. 最後の 行の 最後の 欄を 表示するには どうしたら よいでしょう?
  3. 次の処理を同時に行う awk プログラム all.awkを作成(テキストエディタで)して下さい。(実行するには  awk -f all.awk emp.dat  と入力します。
    1. 前回の授業で作成した acc.dat から、分類が in の金額を合計して 表示しなさい。(変数名に in を使うと「予約語」のため エラーになるので使わないように注意してください。)
    2. acc.dat から 分類が eat, other の金額をそれぞれ合計して表示しなさい。
    3. acc.dat から、1週間の収支(手元に残った金額)を計算して表示しなさい。