コンピュータ実習1 データ処理 学籍番号 氏 名 日本工学院八王子専門学校 電子工学科/電子工学科三年制 1– はじめに UNIX のツールである AWK(オークと読む) を用いてデータ処理を行う。さらに、加工したデータをグラ フ作成ツールを使いグラフ作成を行う。 1.1 AWK とは何か プログラミング言語 AWK は、入力パターンに応じていろいろなアクションを実行することによって、伝 統的なデータ処理からプログラムの試作品作りまでの様々な仕事を処理できるようにしたファイル処理言 語である。 AWK の名前の由来はその開発者である、A.V.Aho、P.J.Weinberger そして B.W.Kernighan の 3 人の頭 文字を集めたものである。 今回の実習ではこの UNIX の AWK と互換性のある GNU AWK1 を使用します。 1.2 実習を始める前に これまでの実習で作成してきたファイルとこれから作成するファイルを区別するために新しいディレク トリを作り,そのディレクトリにデータ処理実習関係のファイルを保存することにします。 • データ処理用の新しいディレクトリをホームディレクトリに作ります。次のように入力します。 これは 1 回だけ実行します。 ¶ ³ mkdir ~/data←µ ´ • ログイン後、データ処理実習のためにワーキング・ディレクトリを data に移動します。(ディレクト リの移動を行わないと作成するファイルはすべてホーム・ディレクトリに保存されます。) ¶ ³ cd data←µ ´ 1 98 などの MS−DOS で利用できるものがある。希望者は FD を持ち、坂部まで 1 2– AWK 入門 2.1 手はじめに 有益な AWK プログラムはたいてい短く、1 行か 2 行で済んでしまう。 いま、あなたの経営する飲食店のアルバイトの名前と時給と労働時間とを 1 行に一人分ずつ書いた、 byte.data1 に以下のような内容のファイルがある。 ¶ byte.data ³ 太郎 鉄郎 小太郎 鬼太郎 六平太 花子 ジョー ミッキー ボブ ルイス 龍一 新之介 松五郎 ももこ あたる ラム テン ゴジラ のび太 スネ夫 900 750 810 1300 890 920 950 1020 630 750 860 660 910 580 935 920 650 1500 550 570 0 11 2 21 17 0 9 7 25 14 20 18 4 12 10 12 8 5 13 15 ここで、ゼロ時間より多く働いたすべてのアルバイトの名前と賃金 を表示したい場合にはどうしたらいいだろうか? これは AWK にはうってつけの問題で、次にように入力すると結果 が得られる。 ¶ ³ gawk ’$3 > 0 { print $1, $2 * $3 }’ byte.data µ ´ µ ´ これはシステムに、コーテーション (’) のなかのプログラムを使い、入力ファイル byte.data からデータ を取り込んで、AWK を起動する事を指示している。 コーテーション内の部分は完全な AWK のプログラムであり、一つのパターン アクション文から成り立っ ている。 まず、パターン$3 > 0 は第三番目の欄がゼロよりも大きいすべての入力行に適合することを意味し、ア クションprint $1, $2 * $3 は、パターンに適合した行の 1 番目の欄と、1 番目と 3 番目の欄の積を表示 することを意味している。 次に、まったく働かなかったアルバイトの名前を表示したい場合は、どうしたらよいだろうか。労働時 間が 0 であるかを調べるようなパターンを指定すればよい。 ¶ ³ gawk ’$3 == 0 { print $1 }’ byte.data µ ´ この場合のパターン$3 == 0 は 3 番目の欄がゼロに等しいような行に適合し、アクション print $1 は、そ の行の最初の欄を印字する。 1 このファイルはディレクトリ/user/awk にある。各自コピーすること。 2 2.2 AWK プログラムの構造 これまでに示したコマンド行では、コーテーションに囲まれた部分が AWK に対するプログラムであった。 AWK プログラムは、次のように一つまたはそれ以上のパターン・アクション文の列から成り立っている。 ¶ ³ パターン アクション パターン アクション ・ ・ ・ ・ ・ ・ µ ´ AWK の基本動作は、入力データを 1 行ずつ走査して、プログラム中にある任意のパターンに適合する行 を探すことである。 すべての入力行は、各パターンと順番に照合され、適合した行に対しては対応する (複数行にまたがって 書かれた) アクションを実行する。次に新しい行を読み込み再び始めから照合を行う。この走査は、すべて の入力を読み終えるまで続けられる。 パターン・アクション文のうちパターンあるいはアクションのどちらかを、省略できる。(両方は省略で きない。) たとえば、$3 == 0 のように、パターンがアクションを伴っていなければ、パターンに適合したすべて の行 (すなわち、その条件が真であるようなすべての行) が表示される。 また、{ print $1 }のように、パターンの無いアクションがあった場合、そのアクション (この場合、 最初の欄を表示すること) が、すべての入力行に対して実行される。 このように、パターンとアクションはどちらも省略可能で、アクションをパターンと区別するためにア クションを大括弧 ({}) で囲む事になっている。 2.3 AWK プログラムの実行 AWK プログラムを実行するには、いくつもの方法があります。 特定の入力ファイル群のそれぞれのファイルに対してプログラムを実行させるには、以下のように入力 します。 ¶ ³ gawk ’ プログラム’ 入力ファイル群 µ ´ たとえば、file1 と file2 に含まれる三つ目の欄がゼロであるようなすべての行の最初の欄のみを表示する には、次のように入力する。 ¶ gawk µ ³ ’$3 == 0 { print $1 }’ file1 file2 ´ コマンド行上では、プログラムは’ によって囲まれている点に注意する。これによって、プログラムのな かの$の様な特殊な文字がシェルによって違う意味で解釈されるのを防いだり、1 行より長いプログラムの 入力が行えるようにしている。 この取り決めは、プログラムが短い (数行) 場合には便利だが、プログラムがもっと長くなる場合にはプ ログラムをファイルに入力し、そのファイル名を指定する方法を使う。それは以下のようにコマンド行か ら入力する。 3 ¶ ³ gawk −f プログラム・ファイル 入力ファイル群←µ ´ −f オプションは、AWK プログラムを指定したファイルから読み込むことを指示する。 2.4 単純な出力 ここでは、これまでに使用したデータファイル byte.data への操作を基本にした短いけれど、典型的な AWK プログラムを紹介する。 AWK に対するデータには数と文字列という、わずか二つのタイプ (型) しかない。ファイル byte.data には、この二つのタイプのデータを空白またはタブで区切って入力してある。 AWK は一度に 1 行ずつ入力からデータを読み込み、それぞれの行を欄に分解する。ここで欄とは、規定 (デフォルト) では空白やタブを含まない文字列を意味する。現在処理している入力行の最初の欄は$1、2 番 目の欄は$2 というように$と欄の順番を示す数字で表現します。 また、行全体は$0 として表現する。欄の数は行ごとに異なっても構わない。 2.4.1 プログラム例 1 行で入力できるものはコマンド行に’ で囲んで入力したほうが素早く結果を得られる。 全部の行の表示 { print } または { print $0 } 特定の欄の表示 { print $1, $3 } 欄の数 NF 2 { print NF, $1, $NF } { print $1, $2 * $3 } 計算と表示 行番号の表示 3 文章の出力 2.5 { print NR, $0 } { print $1, ”さんへの支払額:”, $2 * $3 } 凝った出力 print 文は、素早く簡便な出力に向いるが、望み通りの書式にするには printf 文を使う。 2.5.1 欄の模様替え printf 文の書式を以下に示す。 ¶ ³ printf(書式, 値 1, 値 2,..., 値 n) µ ´ ここで書式は、それぞれの値の表示方法の指定をちりばめながら、字づらどおりに表示される文を含ん だ文字列である。 指定は、%の後ろに値の書式を制御するいくつかの文字 (d,f,s) やその値の桁数が続いたものである。最 初の指定は値 1 の表示方法を指定し、二つ目は値 2 の表示方法指定する、という具合に続ける。 4 したがって、書式の中の%で始まる指定は、表示される値の数と同数が必要である。 ¶ 書式指定の例 1 ³ { printf("%s さんへの支払いは%6d 円です。\n", $1, $2 * $3) } µ ´ この書式の最初の%s は一つ目の値$1 を文字列として、次の%6d は、二つ目の値$2 * $3 の計算結果をを 整数 6 桁の数として表示することを意味している。最後にある n は改行を意味する。 ¶ 書式指定の例 2 ³ { printf("%-8s %6.2f 円\n",$1, $2 * $3) } µ ´ %−8s は名前を文字列として、8 桁の欄に左寄せ表示を指定し、%6.2f は数値を小数点を含めて 6 桁、小 数部を 2 桁での表示を指定している。 2.6 出力の並べ換え AWK 自身には結果を並べ換える機能がないので OS の用意している sort というコマンドを併用する。 ¶ 賃金の小さい順に表示 gawk ’{ printf("%7d %s\n", $2 * $3, $0) }’ byte.data | sort µ ³ ´ まず、AWK により各行を処理し、その結果を sort コマンドに渡し、並べ換えを実現している。(パイプ を利用した処理) 2.7 さまざまな条件による選択 比較による選択 時給 920 円以上の人の名前のみ表 $2 >= 920 { print("%s\n", $1) } 示 計算による選択 賃金が 9000 円より多い人の賃金 $2 * $3 > 9000 { printf("$%6d for %s\n", $2 * $3, $1) } と氏名の表示 文の中身による選択 “太郎” という名前の人のデータを 表示 $1 == "太郎" 特定の文字を含むものによる選択 “郎” という文字を含むデータの表 示 /郎/ 5 2.7.1 パターンの組み合わせ パターンは、かっこや「かつ」、「または」、「否定」を表す論理演算子&&、||、!を使って組み合わせるこ とができます。 条 件 パターン 時給 920 円以上、かつ労働時間 10 時間以上 $2 >= 920 && $3 >= 10 時給 920 円以上、または労働時間 10 時間以上 $2 >= 920 || $3 >= 10 時給 920 円未満でかつ労働時間 10 時間未満ではない !($2 < 920 && $3< 10) 2.8 BEGIN と END BEGIN は、最初に読み込んだファイルの最初の行の前に適合し、END は最後のファイルの最終行を処 理し終わった後に適合する特別なパターンである。 次のプログラムは、見出しを表示するのに BEGIN を使った例である。 ¶ ³ BEGIN { print "名前 { print } µ 時給"; print " " } ´ 6 3– AWK による計算 アクションは、改行やセミコロンで区切られた文の列である。これまでの例では一つの print 文からなる アクションが登場していた。ここでは、単純な数値および文字列演算を実行するための例を紹介する。こ れらの文では、NF のような組み込み変数を使うだけではなく、計算やデータの保管といったような操作を するために、変数を使用する。 3.1 数え上げ ¶ 3.2 10 時間以上働いた人数 ³ $3 >= 10 { byte = byte + 1 } END { print byte } µ ´ ¶ ³ 和と平均の計算 アルバイトの人数 END { print "アルバイトは合計 で", NR, "人" } µ ´ ¶ { pay = END { print print print } µ 3.3 平均賃金の計算 ³ pay + $2 * $3 } "アルバイトの人数は", NR, "人" "総支払額:", pay, "円" "平均支払額は", pay / NR, "円" ´ 文章の操作 AWK の強みの一つは、多くの言語が数を扱うような調子で、文字列を簡単に扱える点である。AWK の 変数は、数だけでなく文字列も記憶できる。 ¶ 最高時給の検索 ³ $2 > maxrate { maxrate = $2;maxemp = $1 } END { print "最も高い時給は", maxemp, "の", maxrate, "円です。"} µ ´ 7 3.4 文字列の連接 新しい文字列は、古い文字列を組み合わせて作ることができます。 3.5 ¶ ³ { names = names $1 " " } END { print names } µ ´ 最後の入力行の表示 ¶ 最後の入力行の表示 { last = $0 } END { print last } µ 3.6 ³ ´ 組み込み関数 AWK には、平方根、対数、乱数などのような算術関数の以外に、文章を操作する関数も含まれている。 これらのうちの一つに、文字列の長さを (文字数) を数える関数 length がある。 ¶ 名前の長さを求める { print $1, length($1) } µ ¶ ³ ´ 行数、単語数、文字数のカウント ³ { nc = nc + length($0) + 1 nw = nw + NF } END { print NR, "行", nw, "語", nc, "文 字" } µ ´ 8 4– 制御文 AWK には決定を下すための if-else 文や、ループを書くためのいくつかの文が用意されているが、これら はすべて C 言語のものをモデルにしている。これらは、アクションでのみ利用できる。 4.1 if else 文 次のプログラムは、時給が 900 円より多いアルバイトに支払われる賃金の合計と平均を計算するもので ある。このプログラムでは、平均賃金を計算するさいにゼロで割るのを避けるために if を使っている。 ¶ ³ $2 > 900 { n = n + 1; pay = pay + $2 * $3 } END { if (n > 0) print n, "employees, total pay is", pay, "average pay is", pay/n else print "no employees are paid more then 900/hour" } µ ´ byte.data に対する出力はどうなるか実際に試しなさい。 この if else 文では、if に続く条件が評価され、その値が真ならば最初の print 文が、そうでなければ二つ 目の print 文が実行される。 4.2 while 文 while 文は、条件と本体から成る。本体中の文は、条件が真である間繰り返し実行される。このプログラ ムは、入力された 1 番目の数から 2 番目の数までを 3 番目の数の間隔で変化させたときの和をその都度求 め、表示するものである。 9 ¶ # # # { ³ 和の計算 (while 文) 入力:開始値 終了値 間隔 i = $1 while (i <= $2 ) { sum = sum + i printf("\t%6d から%6d までの和は%10d です。\n",$1,i,sum) i = i + $3 } } µ ´ ここでの条件は、while の後ろにある括弧で括られた式であり、ループ本体は中括弧で囲まれた三つの文 である。#からその行の最後までの文は注釈 (コメント) で、AWK には無視されるが、このプログラムで 何が行なわれているかを理解したい場合には手助けになる。 このプログラムを実行した例を次に示す。 gawk -f while.awk<RETURN> 1 10 1<RETURN> 4.3 for 文 もう一つの文 for は、ほとんどのループの中に表れる初期化とテストとインクリメントを、一つの行に詰 め込んだものである。先程の例を for を使って書いてみると次のようになる。 ¶ # # # { ³ 和の計算 (for 文) 入力:開始値 終了値 間隔 for (i = $1; i <= $2; i = i + $3) { sum = sum + i printf("\t%6d から%6d までの和は%10d です。\n",$1,i,sum) } } µ ´ 初期化 i = $1 は、一度だけ実行される。次に条件 i <= $2 がテストされ、それが真ならばループの本体が 実行される。その後 i = i + $3 が実行され、再び、条件テストによって、ループの次の繰り返しが始まる。 10 5– 配列 AWK には、関係のある値の集まりを格納するために配列が用意されている。この配列によって AWK は かなりの力を持つようになったのであるが、ここでは、単純な例を一つだけ示すのにどどめる。 次のプログラムは、入力を行ごとに逆順で印字する。最初のアクションは、入力行を配列 line の要素に 順番に、つまり最初の行を line[1] に、2 行目を line[2] に、という具合に代入している。END アクションで は、最終行から最初の行へと配列の内容を印字するのに、while 文を使用している。 ¶ ³ # reverse END { line[NR] = $0 } # 各入力行を記憶する { i = NR while (i > 0) { print line[i] i = i - 1 } } # 行を逆順で印字する µ ´ byte.data に対する出力がどうなるか確認する。 同じ例を for 文を使って書くと次の様になる。 ¶ ³ # reverse { line[NR] = $0 } END # 各行を記憶する { for (i = NR; i > 0; i = i -1 ) print line[i] } µ ´ 11 6– 便利な「一行野郎」たち AWK は、ある程度複雑なプログラムを書くのにも利用できるが、多くの有用なプログラムは、我々が今 まで見てきた以上に複雑なものではない。以下に、手頃で (あるいは) 教訓的な短いプログラム群を示す。 1. 入力行の総数を印字する。 END print NR 2. 10 行目の入力行を印字する。 NR == 10 3. すべての入力行の最後の欄を印字する。 print $NF 4. 最後の行の最後の欄を印字する。 END { field = $NF } { print field } 5. 4 個より多い欄を持つすべての入力行を印字する。 NF > 4 6. 最後の欄が 4 より大きいようなすべての入力行を印字する。 $NF > 4 7. すべての入力行の欄の総数を印字する。 END { nf = nf + NF } { print nf } 8. Beth を含む行の総数を印字する。 /Beth/ { nlined = nlines + 1} END { print nlines } 9. 最も大きい第 1 欄とそれを含む行を印字する ($1 のどれかは正であると仮定する) $1 > max { max = $1; maxline = $0 } END { print max, maxline } 12 10. 少なくとも一つの欄を持つすべての行を印字する。 NF > 0 11. 80 文字以上の長さを持つすべての行を印字する。 length($0) > 80 12. それぞれの行の欄の数とその行自身を印字する。 { print NF, $0 } 13. 任意の行の最後の二つの欄を逆順で印字する。 print $2, $1 14. すべての行を最初の二つの欄を交換して印字する { temp = $1;$1 = $2;$2 = temp;print } 15. すべての行を最初の欄を行番号に置き換えて印字する $1 = NR;print 16. すべての行を二つ目の欄を消去して印字する。 $2 = ””; print 17. すべての行の欄を逆順で印字する。 { for (i = NF; i > 0; i = i - 1) printf("%s ", \$i) printf("\n") } 18. すべての行の各欄の合計を印字する { sum = 0 for (i = 1; i <= NF; i = i + 1) sum = sum +\$i print sum } 19. すべての行のすべての欄を合計して、その値を印字する。 END { for (i = 1; i <= NF; i = i + 1) sum = sum + \$i } { print sum } 20. 各欄の値を絶対値に置き換えてからすべての行を印字する。 { for (i = 1; i <= NF; i = i + 1) if ($i < 0) $i = -$i print } 13 目次 1 はじめに 1.1 AWK とは何か . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 実習を始める前に . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 1 2 AWK 入門 2.1 手はじめに . . . . . . . 2.2 AWK プログラムの構造 2.3 AWK プログラムの実行 2.4 単純な出力 . . . . . . . 2.4.1 プログラム例 . . 2.5 凝った出力 . . . . . . . 2.6 欄の模様替え . . . . . . 2.7 出力の並べ換え . . . . . 2.8 . . . . . . . . . . . . . . . . . さまざまな条件による選択 . 2.8.1 パターンの組み合わせ 2.8.2 BEGIN と END . . . . 3 AWK による計算 3.1 数え上げ . . . . . . . 3.2 和と平均の計算 . . . 3.3 文章の操作 . . . . . 3.4 文字列の連接 . . . . 3.5 最後の入力行の表示 3.6 組み込み関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 2 3 3 4 4 4 4 5 5 6 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 7 7 7 8 8 8 4 制御文 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1 if else 文 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 while 文 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3 for 文 10 5 配列 11 6 便利な「一行野郎」たち 12 i AWK 演習レポート 1 学籍番号 氏名 次の各問いに対するプログラムを作り、それを書きなさい。 1. 0 時間より多く、10 時間未満の人の氏名と労働時間を表示する。 2. 10 時間以上、20 時間未満の人の氏名,労働時間,賃金を表示する。 3. 賃金 5000 円以上,10000 円未満の人の氏名,賃金を表示する。 4. 時給 500 円以上で,労働時間 10 時間以上の人の氏名と賃金を表示する。 5. 時給 500 円台の人の氏名,時給,賃金を表示する。 6. 労働時間が一桁の人の氏名,労働時間,賃金を表示する。 7. 時給 700 円台かまたは労働時間 20 時間以上の人の氏名,時給,賃金を表示する。 8. 時給 800 円台で賃金が 10000 円以上の人の氏名,時給,賃金を表示する。 9. 時給 900 円台で賃金が 10000 円以下の人の氏名,時給,賃金を表示する。 10. 賃金 10000 円以上かまたは時給 900 円以上の人の氏名,賃金,時給を表示する。 日付
© Copyright 2024 Paperzz