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

目次

今回の内容は awkというディレクトリを作成して、その中で実行してください

AWK とは

AWK はファイル処理を目的とした一種のプログラム言語です。 grep がパターンを 含む行を表示するのに対して、 awk は パターンを含む行にだけ、アクションと呼ばれる 処理を行ないます。
#名称の AWK は、開発者のアルフレッド・エイホ(Alfred Aho)、ペーター・ワインバーガ(Peter #Weinberger)、ブライアン・カーニハン(Brian Kernighan)の3人の頭文字を取って付けられたもの#です。

参考書 プログラミング言語AWK (新紀元社情報工学シリーズ) A. V. エイホ、P. J. ワインバーガー、B. W. カーニハン、 Alfred V. Aho (2004)


基本的な文法は以下のとおりです。

awk  ' パターン部{アクション 部} '  ファイル名
 
’’の中身が、awkのプログラムです。プログラムはパターン部とアクション部に分かれています。
awkのパターン、アクション部では、各行の第n欄の内容を $nで参照することができます。

ここで、tmp.datの内容を以下のとおりとします。

0     1     3
1     1     4
0     2     5
 

awk ' $1> 0 { print $1, $3}' tmp.dat

というコマンドは tmp.datの第1欄が0以上のとき第1欄,、第3欄を表示せよ、という意味になります。printはその後に続くデータを表示するという、アクション部で用いられるコマンドです。

したがって実行結果は

1    4

となります。
 

はじめに

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

ある週の 勤務時間を 表に したのが 以下の とおりで、 この データは emp.dat と いう名の ファイルに 作って おく ことに します。ここで第1欄が名前、第2欄が時給、第3欄が勤務時間を表すものとします。

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欄との積 を 表示する ことを 指示します。単に欄の表示だけでなくその演算結果も表示できることに注意してください。

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

 
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 }
は入力行の欄の数と、その行の最初と最後を表示します。従って $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 " " では 空行の 表示を おこなって います。

問題

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

1. 下記の作業を使用とするときの awkの実行文と、その結果を示しなさい
  (1) emp.dat の中から Mark の給料を計算して表示する
  (2)emp.dat の中から 20時間以上働いた人の名前を表示しなさい。

2. 自分の 1週間のこづかい帳 を acc.dat という名前で作成して(補足のとおりに作成) 
 以下の問題にこたえなさい.
 (1) catでacc.datの内容を示しなさい
   (2) awkで acc.dat の中から other に入れた項目表示する実行文と、その結果を示しなさい(例、 
       socks books etc)
   (3) awkで acc.dat の中から lunch を食べた日を表示しなさい。

:注:ファイル名の入力を忘れると、標準入力を読もうとします。 Csh のプロンプトが出てこなくなりますので、Control+D で 標準入力を終了させるか、Control+C でプログラムを終了させて ください。


補足

acc.datのファイルの中身は 日付  大品目  少品目    金額の順に記述されているものとする。

(最低でも10行のエントリーを作成してください)


7/1   food    lunch    2010
7/1   other   socks    200

.......