配付資料

計算機科学概論 ユーティリティとフィルタ (2) (2015 年 11 月 27 日)
山本 光晴
1
正規表現を用いる UNIX のフィルタ
grep, egrep (または grep -E), fgrep (または grep -F)
• 正規表現がマッチする文字列を含む行を出力。 (「-v」オプションで含まない行を出力。)
• grep, egrepでは前回のプリントの表のようにパターンとして書ける正規表現の種類が異なる。
• fgrepは特殊文字を解釈しない (指定した文字列をそのまま探す)。
% grep ’^[AIUEO]’ < fuken.data
% egrep ’record|array’ *.p
% ps auxww | grep -v ^root
引数としてファイル名を複数取ることも可能。
終了ステータスはマッチする行があれば 0(正常終了、真)、なければ 0 以外 (異常終了、偽) になる。
sed
• trが文字単位の置換であったのに対し、sedは文字列単位の置換に用いられる。
• 基本的には「sed s/パターン/置き換え文字列/フラグ」の形式。パターンはgrepで使用する正規表現で指定。
– 置き換え文字列中で「&」はパターンがマッチした文字列全体、「\n 」はgrepと同様にパターン中で n 番
目に現れる\(. . . \) がマッチしたものに置き換わる。
– 置き換え文字列中で「&」や「\」自体を表したいときは、それらの文字の直前に「\」をつける。
– フラグで「g」を指定するとパターンがマッチしたもの全てを置換。指定しないと、行の中で最初にパター
ンがマッチしたもののみを置換。
– sのあとの区切り文字「/」は「\」以外の普通の文字ならかわりに使える。
$ for f in mondai*.pas; do
ファイル名の一括置換 (sh)
>
mv "$f" "‘echo "$f" | sed ’s/^mondai\(.*\)\.pas$/ex-\1.p/’‘"
> done
% pwd | sed "s|^$HOME|~|"
(ただしホームディレクトリのパス名に特殊な文字が入っていない場合)
• sed自体は置換以外のテキスト編集を行うこともできるのだが、直感的にわかりにくいので、もっぱら文字列
単位の置換を行うフィルタとして用いられる。
2
awk
テキスト処理を行うための小さな言語。文法が C に似ているので慣れておいて損はない。なお、この資料だけでは
到底全ては説明しきれないので、オンラインマニュアルなどを参照せよ。
• awkのプログラムは、
パターン { アクション }
パターン { アクション }
:
という形式。アクションは文 (例: 「a = b + 1;」、「print $1;」) の列1 。
• sedと同様、入力を行ごと (正確にはレコードごと) に処理する。行がパターンで示される条件を満たすとき、
対応するアクションが実行される。パターンが空のときは文の列は常に実行される。
• 実行するときは、「awk プログラムテキスト [入力ファイル] 」または、「awk -f プログラムファイル [入力
ファイル] 」。シェルスクリプトと同様に、
#!/usr/bin/awk -f
プログラムテキスト
という中身の実行ファイルを作ってもよい。
1 awk
では文の後が改行か「}」の場合には「;」は必要ないのだが、この資料では C の文法に合わせて「;」を付けることにする。
14
フィールド
• $n で n 番目のフィールドが取り出せる。$0は行全体
表示
• 普通の表示printと書式指定つき表示printfがある。printfでは書式中の「%s」、「%d」、「%f」が第 2 引
数以降で指定された文字列、整数値、実数値でそれぞれ置き換わる。% の後で表示幅を指定 (正の数で右揃え、
負の数で左揃え) することも可能。
% who | awk ’{print $1;}’
% awk ’{printf("%-10s %-8s %6d %6d\n", $1, $2, $3, $4);}’ < fuken.data
県名・地方・人口・面積・欄を揃えて出力 (書式中の \n は改行)
パターン
• パターンとして書けるのは「/(egrep で使う方の) 正規表現/」 (正規表現がマッチする文字列を入力行が含む)、
条件式、BEGIN, ENDなど。BEGIN, ENDはそれぞれ入力テキストの最初と最後に対応。条件式には「式 == 式」
(等しい)、 「式 != 式」 (等しくない)、「式> 式」などの比較演算、「文字列 ~/ 正規表現 /」 (正規表現が文
字列にマッチする)、「文字列 !~/ 正規表現 /」 (正規表現が文字列にマッチしない)、「! 条件」 (条件の否定)、
「条件 && 条件」 (and)、「条件 || 条件」 (or) などが書ける。「パターン1 , パターン2 」で、 パターン1 が成
立してから パターン2 が成立するまでの行、という指定も可能。
% awk ’$2 == "Kantou" {print;}’ < fuken.data
関東地方のみ表示
printfの書式もそうだが、文字列は「"」で括る。
変数
• shと異なり、awkでは文字列の他に数値を扱うこともでき、変数にそれらの値を格納することができる。変数
への代入は「変数 = 式」の形。演算と代入を組み合わせた「変数 += 式」 (変数 = 変数 + 式と同じ) や、「変数
++」 (1 を加える)、 「変数 --」 (1 を減じる) などの形もある。
% awk ’{printf("%-10s %6d %6d %7.1f\n", $1, $3, $4, 1000*$4/$3);}’ < fuken.data
県名・面積・人口・人口密度を欄を揃えて出力
• 変数値を文字列として扱うか数値として扱うかは文脈と変数の中身によって決まる。なお、式を並べて書くと
文字列としての連結が行われる。
• 変数の宣言は必要ない。新しい変数は文字列としては空文字列、数値としては 0 に初期化される。
% awk ’$2 == "Kantou" {sum += $4;} END {print sum;}’ < fuken.data
関東地方の人口の総和
• NR(現在何行目か) やNF(現在行のフィールド数) など、awkが自動的に設定する変数がいくつかある。
% awk ’{printf("First field: %s, Last field: %s\n", $1, $NF);}’
シェルとの変数の扱いの違いに注意。「i」は変数iの値、「$i」は変数iの値が i であったときの第 i フィール
ドをそれぞれ表す。
制御構造
• awkにも「while (条件式) 文」や「if (条件式) 文 [ else 文] 」などの制御構造がある。文法は異なるが、
Pascal からの類推で対応できるはず。
• Pascal での「begin 文; …; 文 end」に対応するのは、「{ 文 … 文 }」。ここで、 Pascal では「a := 1」
が文であったのに対し、 awk や C では「a = 1」は式であって、セミコロン付きの「a = 1;」が文であるこ
とに注意。式としての代入がどのような値を持つかは次回以降の C のところで扱う。
• forだけは少し異なる。「for (式1 ; 条件式; 式2 ) 文」は、「式1 ; while(条件式) {文 式2 ;}」とほぼ同じ。
% awk ’{for (i = NF; i > 1; i--) printf("%s ", $i); print $1;}’ < fuken.data
フィールドを逆順に表示
15
連想配列
• Pascal の配列は添字に部分範囲型 (典型的には整数のある区間) しか使えなかったが、awkの配列は添字に文字
列を用いることができる。これを連想配列と呼ぶ。連想配列も宣言は必要ない。要素は変数と同様に空文字列
ないし 0 に初期化される。
% awk ’{area[$1] = $3;} END {print area["Chiba"], area["Tokyo"];}’ < fuken.data
• 連想配列中の全ての添字について何か処理をしたいときは、「for (変数 in 連想配列) 文」の形式を用いる。
% awk ’{ppl[$2] += $4;} END {for (r in ppl) printf("%-8s %6d\n", r, ppl[r]);}’ < fuken.data
地方ごとの人口の総和を出力
その他
awkには数値や文字列を操作するためのsqrtやlengthなどの組込み関数がいくつかある。これらに関してはオン
ラインマニュアルなどを参照せよ。
3
問題
以下のいずれかの問題を選択して回答せよ。
問題 4a
シェルや今回登場したユーティリティを使用し、fuken.dataのようなテキストファイルを読んで、 HTML
での表 (テーブル) を出力するコマンドを作成せよ。もとのテキストファイルに「<」, 「>」, 「&」が含
まれている場合は HTML のタグの一部とみなされないよう、適切な処理をする必要がある。
また、有用と思われる機能を各自考えて付け加えよ。どのような機能を付けたかをきちんと説明するこ
と。例としては、
• もとのテキストファイルの区切り文字を指定できるようにする。
• 単体で Web ページを構成できるような出力を生成する。 (「<html> ∼ </html>」まで含む) か、
Web ページの部品として使用できるような出力を生成する (「<table> ∼ </table>」のみ) かを
制御できるようにする。
• 各フィールドが何を表しているかの見出しを付加できるようにする (<th> タグ)。
などが考えられる。
HTML で表をどう記述するかは、以下の資料を参考にするとよい。
http://www.w3.org/TR/html5/tabular-data.html
http://momdo.github.io/html5/tabular-data.html
問題 4b
シェルや今回登場したユーティリティを使用し、単語当てゲームを作成せよ。ゲームの内容は以下のよ
うなものであるとする。
1. 答えとなる単語が /usr/share/dict/words から ($$ などを利用して) 自動的に選ばれる。
2. 最初は、単語中の英字が全て「_」で伏せられてプレイヤーに提示される。
3. プレイヤーは、その単語に含まれる英字を 1 文字予想して入力する。
4. 入力した英字がその単語に含まれていれば、その英字が伏せられていた部分のみが開示される。そ
うでなければ再度伏せられたまま表示される。
5. 3 ∼ 4 を単語中の全ての英字が当たるまで繰り返す。
細かい部分の仕様は自分で決めてよいが、どのように決めたかをレポートに明示すること。
ヒント: sh で標準入力から入力を 1 行読むには、「read NAME 」とする (変数 NAME に読んだ入力が
格納される)。
提出期限・場所
問題 4 の提出期限を 1 月 12 日 (火) 17:00 とする。
提出場所は、理学部 2 号館 5F 510 前のレポート提出箱。
16