![]() |
Perl で grep grep を作る |
| 西広島ドットコムへようこそ! |
| |トップ|新着情報|検索|サイトマップ| |
|
Perl で grep を作るUNIXの世界で非常によく使われるコマンドの1つがgrepで、 働きは簡単に言って、ファイルから指定された文字列を含む行を検索して表示、というものである。 grepにはいろいろなオプションがあって便利になっているが、 ここではPerlを使い、ごく簡単なgrepを作成してみよう。 まず、次のようなスクリプト3.plを作成してもらいたい。 if ($_ =~ /太郎/) {
print $_;
}
続いて、次のコマンドを実行してみよう。 perl -n 3.pl pt.dat これはほとんど2.plと同じである。 6を含む行の代わりに太郎を含む行が取り出されたわけである。 Perlでは、$で始まる1まとまりの文字列は変数と呼ばれる。 数学で、変数xとか変数yとかいう、あれである。 変数には「1」とか「2」とか、数字が代入できたと思うが、 Perlの変数には「太郎」とか「花子」とか、文字列も代入できる。 $_という変数は特別で、 Perlはデータを1行読むごとに、その内容をこの変数に格納する。 if文は次のようにして使う。 if (条件式) ブロック ちなみに条件式は真か偽かの値をもつ式で、 Perlでは、0、空文字列''''、空リスト()''、未定義値が偽、 それ以外は真となる(未定義値などは後述)。 ブロックはいくつかの文を中かっこ{}で囲んだものをいう。 ここではprint文の意味は容易にわかると思うので、条件式にしぼって説明します。 $_ =~ /太郎/の中の=~はパターンマッチ演算子と呼ばれ、 $variable =~ /パターン/ して使う。 左辺の$variableの内容が右辺のパターンにマッチしたとき真になる。 パターンは通常、正規表現(後述)を用いて記述し、 左辺の変数を省略した場合 �妊侫�襯箸諒竸�_の内容が使われる。 否定のパターンマッチ演算子!~を使うと、 マッチしないとき真になる。 $variable !~ /パターン/ パターンマッチ演算子はパターンの末尾にオプションを付けることができる。 $variable =~ /パターン/オプション 使用できるオプションは、
grepを改良するスクリプトを改良し、3a.plとする。 while (<>) {
chomp;
if ($_ =~ /太郎/) {
print "$_\n";
}
}
続いて、次のコマンドで実行してみよう。 perl 3a.pl pt.dat 同じ結果が返ってきたはずである。 コマンドラインから-nオプションが消えた。 実はこれにより、スクリプト全体をwhile (<>) { }で囲まなければならない。 これまでは、暗黙のうちに-nオプションがやっていてくれたのだが、 いつもこれに頼るわけにはいかないので、今回ははずしてみた。 while文は次のようにして使う。 while (条件式) ブロック 意味は条件式が真の間、ブロックを実行しつづけるということである。 while文の条件式に<>を指定した場合には特別な意味があって、 標準入力からデータが送られる間は読み続けようとする。 通常Perlはスクリプトファイルの次に書いたファイル(ここではpt.dat)のデータを 標準入力として読みこむので、pt.datの中味がある限り、後続のブロックが実行される。 chompは読みこんだ各行末尾についている改行文字を削除する。 これまでは面倒なため、使わなかったが、データを読みこむ場合は使うべきだ。 こうしないとエラーが起こることがある。 また、各文の終わりには;(セミコロン)をつける約束になっている。 その代わり、"$_\n";と\n(改行文字を表す)がついている。 ちなみに""で囲まれた文字列の中では、 次のような特殊文字(エスケープシークエンス)が使える。
また""(ダブルクォーテーション)で囲まれていると変数は展開されるので、 $_の部分は各行の内容で埋められる。 ' '(シングルクォーテーション)で囲んだ文字列の中では変数が展開されないので注意しよう。 grepをさらに改良するスクリプトを改良し、3b.plとする。 #! /usr/bin/perl
# 3b.pl
# Usage: perl 3b.pl pt.dat
$str = "太郎";
while (<>) {
chomp;
if ($_ =~ /$str/o) {
print "$_\n";
}
}
実行は perl 3b.pl pt.dat スクリプト内では#以後行末までは無視されることになっており、 通常コメントを記入する。 1 行目は特殊なもので、UNIXなどでは、これにより、 ./3b.pl pt.dat だけでスクリプトが実行できる。 ./はカレントディレクトリにあるという意味の接頭語。 ただし、これに先立ち、 chmod +x 3b.pl として、スクリプト3b.plに実行属性を与えておく必要がある。 WindowsでもCygwinを使ったりしていると、#! perlなどとして同様に実行できる。 2、3行目は純粋なコメントで、スクリプト名、使用法のメモなどを書き込んでいる。 $str = "太郎"の部分に注意しよう。 これは自分の決めた変数$strに「太郎」という文字列を代入している。 Perlでは、$に続く英字または_、その後に英数字または_がくると、変数になる。 変数はPerlに元々使われていないものであれば自由に作ることができる。 文字列は""または' 'で囲む。 2つの違いは前述の通り。 また$_ =~ /$str/oの部分には、この文字列$strを使い、 一度決めると変更しないのでoオプションをつけた、というわけである。 grepを本気で改良するスクリプトを改良し、3c.plとする。 #! /usr/bin/perl
# 3c.pl
$str = shift;
$file = shift;
open(IN, "$file") or die "File not found.\n Usage: perl 3c.pl pattern file\n";
while (<IN>) {
chomp;
if ($_ =~ /$str/o) {
print "$.: $_\n";
}
}
close(IN);
実行は perl 3c.pl 6 pt.dat などとすること。 改良点の1つ目は、shiftという関数の使用で、 これによりコマンドラインに書いた引数が順番に取り出されて、変数にセットされる。 すなわち、$strには6が、$fileにはpt.datが代入される。 こうすると、検索するパターンをその都度簡単に変更できる。 関数openで始まる1行は明示的にファイルを開いている。 これまでは、Perlが行う標準入力の機能によりかかっていたが、 これがいつも通用する�箸聾造蕕覆い里如�[K 自分でファイル名を指定して開いている。 open(ファイルハンドル, "パス名") 通常ファイルハンドルは大文字のIN, OUTなどを使う (STDIN, STDOUT, STDERRはそれぞれ標準入力, 標準出力, 標準エラー出力として、 予め開かれているので注意すること)。 パス名はC:\scripts\pt.datとか~/scripts/pd.datなどである。 パス名の前に>をつけると書き込み用、 >>をつけると追加書き込み用、 |をつけるとパイプ用となる (パイプにはzcat $file|のように、入力時に他のコマンドの出力を使う形式もある)。 開いたファイルは使わなくなったら、以下の書式で閉じておく。 ここでは、whileループが終わった時点で不要なので閉じている。 close (ファイルハンドル) or dieの部分は慣用句といってもいい表現で、 前項の処理がうまくいかなかった場合、dieという関数に制御がうつる。 dieは後続する文字列を標準エラー出力(通常標準出力と同じく画面)に表示して、 Perlを強制的に終了する。 この場合、読み込むファイルが存在しないので、予期せぬ事態であるから、即座に終了させる。 ここで、使用方法を画面に出しておくと親切だ。 先ほどはファイルハンドルなどを使わなかったから、 while (<>)でよかったが、 明示的にファイルを開いた場合は、 そのファイルハンドルを<>の間に書かなくてはならない。 こうするとwhileループはそのファイルハンドルに結び付けられたファイルから 1行ずつ読んでは$_にセットし、後続するブロックを実行する。 <ファイルハンドル>の注意点上記の例は$line = <IN>のようにして$lineという変数に代入してもよい。 また、実は特殊変数$/の値(デフォルトでは\n)をundefに変更すると、 ファイルから一気に全内容を読み出すことができる。 open(IN, "3c.pl"); $/ = undef; $_ = <>; print "$_"; close(IN); "$.: $_\n"の部分に使われている$.は、 現在読みつつあるファイルの行数を意味する。 サイズの大きなファイルなどの場合、便利である。 行数だけでなく、その前にファイル名が出力されるように変更したスクリプトを3d.plとし、 3d.plからrという文字が含まれる行を検索するよう、実行してみよう。 |
| |サイトポリシー|プロフィール|地図|お問合せ| |
2007- (C) Nishihiroshima.com
|