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

目次

AWK とは

Awk は ファイル処理を 目的とした、 一種の プログラム言語です。 grep が、 パターンを 含む 行を 表示する のに 対して、 awk は パターンに 応じた アクションと 呼ばれる 処理を 行ないます。

はじめに

いま、 あなたの 経営する 会社に、 Beth, Dan, Kathy, Mark, Mary, Susie の 6人の 従業員が いて、 それぞれ、 違う 時間給を 受け取って いると します。 また、 その会社は フレックス タイム制を とっていて それぞれが 働いている 時間も 違う とします。

ある週の 勤務時間を 表に したのが 以下の とおりで、 この データは 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 を 使って、 次の ように 入力 すれば よいことに なります。
sw99% awk '$3> 0 { print $1, $2 * $3 } ' emp.dat
Kathy   40
Mark   100
Mary   121
Susie 76.5
この コマンドラインは、 引用符の 中の プログラムを 使って、 入力ファイル emp.dat から データを 読み込んで awk 処理する ように しています。

引用符の 中の プログラムは、 パターン部と、 {} で 囲まれた アクション部 に 分れて います。 パターン $3 > 0 では、 3 番目の 欄が、 ゼロより 大きいような 行に 適合する ことを 表します。 アクション { print $1, $2 * $3} で、それぞれ 適合した 行の 第1欄、 第2欄と 第3欄との積 を 表示する ことを 指示します。

$ や >, { ,} と いった 文字が、 Cシェルで 特殊な 意味を 持つため、 シングルクォート (’) で エスケープしている ことにも 注意して ください。

働かなかった 従業員の 名前を 印字するには、 次の ように します。

sw99% awk '$3 == 0 { print $1 } ' emp.dat
Beth
Dan
ここでは、 パターン $3 == 0 は 3番目の 欄が ゼロに 等しいような 行に 適合し、 アクション { print $1} で その 行の 最初の 欄を 表示します。

Awkの構造

Awk プログラムは ひとつ以上の、 パターン { アクション} の 列 から なって います。 次の ような コマンド行を 入力して みて下さい。複数行に わたった コマンドの 入力に なりますので、 リターンを 押して しまってから 間違いに 気が 付いたら Ctrl+C で中断し、 最初から 入れて 下さい。
sw99% awk \
'$3 > 0 { print $1, $2 * $3 } \
$3 == 0 { print $1 } ' emp.dat 
Beth
Dan
Kathy 40
Mark 100
Mary 121
Susie 76.5
それぞれの パターンが 適合する 行に、 アクションの 処理が なされている ことが わかると 思います。

パターンか アクションの どちらかを 省略する ことも できます。 アクションを 省略したとき、 その行 全体が 表示されます。 (grepと 同じに なります) パターンを 省略した ときは、 全ての 行に ついて アクションの 処理が 行なわれます。 ですから、 emp.dat に ある 従業員の 名前を 全部 表示するには、 次の ように すれば よいことに なります。

sw99% awk ' { print $1 } ' emp.dat
Beth
Dan
Kathy
Mark
Mary
Susie

Awk の実行

Awk は フィルター コマンドでも あります。 もし、 対象 ファイルの 指定が ないときは 標準入力 からの 行を 処理します。
sw99% cat emp.dat | awk ' { print $1 } '
Awk プログラムが 長く なると、 コマンド ラインに いちいち 記述するのは 面倒です。 エラーが 起こった ときの 対応も できなく なります。 このため、 awk プログラムを ファイルに 記述して おくことが できます。 次の ような 中身の ファイルを pay.awk という 名前で 作成しましょう。
$3 > 0 { print $1, $2 * $3 }
$3 == 0 { print $1 }
Awk を 起動する 時に、 -f オプションで プログラム ファイルを 指定する ことが できます。
sw99% awk -f pay.awk emp.dat 

単純な出力

全部の行の表示

print文は 引数を 持たない時、 入力行 そのものを 表示します。 ですから、
{ print }
は 入力 したものを 全て 表示する ことに なります。 また, $0 は 行全体を あらわしますので、 おなじことが
{ print $0}
でも できることに なります。

特定の欄の表示

print文は 1個 以上の 項目を 同じ 行に 出力する ことが できます。 例えば、 それぞれの 入力行の 最初と 3番目の 欄を 表示する プログラムは 次の ように なります。
{ print $1,$3 }

欄の数NF

欄の 番号を 表す 変数を、 $ の 後に 書く ことも できます。 例えば、 変数 NF は 現在の 入力行の 欄の 数を 持って います。 したがって、
{ print NF, $1, $NF }
は入力行の欄の数と、その行の最初と最後を表示します。

計算

{ print $1, $2 * $3 }
のように 計算式を 書いて、 その 結果を 表示させる ことも できます。 Awk では、+(加)、 -(減)、 *(乗)、 /(除) の ほかに C言語で 使える さまざまの 演算が 利用 できます。

行番号の表示

変数 NR は それまでに 読み込んだ 行の 数を 持って います。 入力行の 各行に 行番号を ふるには、 次の ような プログラム を 用います。
{ print NR, $0 }

文章の出力

欄や 計算結果の 間に 文字を 表示する ことも できます。
{ print "Total pay for", $1, "is", $2 * $3 }
このほかに、 printf と いう 関数を 使うと、 さらに 凝った 表示を する ことが できます。 その 方法に ついては、 C 言語で printf を 習ってから、 参考書を 見て 覚えて 下さい。

パターンによる選択

Awk では パターン部を 使って、 興味の ある 行だけを 選択できます。 選択には さまざまの 方法を 用いる ことが できます。

比較による選択

$2 >= 5 の ように、 特定の 欄の 値が ある数より 大きい (または 小さい) ことを 基準に 選択を おこなう ことが できます。 比較を 行なう 演算子には、
> 左辺が 右辺より 大きい
>= 大きいか 等しい
== 等しい
<= 等しいか 小さい
< 小さい
があります。 等しいことを 表すのに、 等号を 2つ 重ねる ことに 注意して ください。

計算による選択

比較の 対象には、 計算の 結果を 使う ことも できます。 emp.dat の 中の 賃金が 50ドルを 越える 従業員を 選ぶには、
$2 * $3 > 50
という パターンを 使います。

文の中身による選択

Grep で 行なって いた ように、 特定の 文字列を 含む 入力行を 選択する ことも できます。 次の プログラムでは、 最初の 欄 が Susie で あるような 全ての 行を 表示します。
$1 == "Susie"
行の 中の どこかに Susie と いう 文字が あれば 選択する ので あれば、
/Susie/
という 斜線で 囲んだ パターンを 用いる ことが できます。 また、 2重引用符や 斜線で 囲んだ 文字列には、 grep で 学んだ 正規 表現 (regular expression) を 使う ことも できます。

パターンの組み合わせ

かっこや 「かつ」 (&&) 「または」 (||) 「否定」 (!) を 使って、 パターンを 組み合わせる ことが できます。 例えば、 次の プログラムは $2 が 4以上か、 $3が 20以上の 行を 表示します。
$2 >= 4 || $3 >= 20

BEGIN と END

BEGIN は 最初に 読み込む ファイルの 最初の 行の 前に 適合し、 END は 最後の ファイルの 最終行を 処理し 終わった 後で 適合します。 次の 例では、 見出しの 印字に BEGINを 利用して います。
BEGIN { print "NAME\tRATE\tHOURS"; print " " }
{ print }
セミコロンで 区切ることで、 複数の 文を ひとつの アクション部に 書く ことが できます。 また print " " では 空行の 表示を おこなって います。

練習

とりあえず、1行のコマンドでできそうなものを練習します。 ファイル名の入力を忘れると、標準入力を読もうとします。 Csh のプロンプトが出てこなくなりますので、Control+D で 標準入力を終了させるか、Control+C でプログラムを終了させて ください。
  1. emp.dat の中から Mark の給料を計算して表示しなさい。
  2. emp.dat の中から 20時間以上働いた人の名前を表示しなさい。
  3. 自分の 1週間のこづかい帳 を acc.dat という名前で作成してください。
    acc.dat の中から食費の金額を取り出して表示しなさい。
  4. acc.dat の中から other に入れた項目を表示しなさい(例、socks books etc)
  5. acc.dat の中から lunch を食べた日を表示しなさい。
以上の実行コマンドと acc.dat の内容を担当教官へメールで送信しなさい。