ファイルAに書かれた文字列で、ファイルB内を検索するperlスクリプト(findStr.pl)を作成した。使い方は簡単で「perl findStr.pl "ファイルA" "ファイルB"」で実行する。
例えば、ファイルAの中身が
aaa
bbb
ccc
となっていて、ファイルBの中身が
aaa
ddd
eee
となっていたら、「aaa」を出力する。
use strict; use warnings; use Getopt::Long; my $notExist = 0; my $fromFile; my $toFile; GetOptions( 'notExist' => \$notExist, 'fromFile=s' => \$fromFile, 'toFile=s' => \$toFile, ) or die 'Usage: findStr.pl {-f|fromFile} <Keyword file> {-t|toFile} <target file> [-n|notExist]'; open(my $fromFh, "< $fromFile") or die "Can't open $fromFile: $!"; open(my $toFh, "< $toFile") or die "Can't open $toFile: $!"; while (my $checkLine = <$fromFh>) { next if ($checkLine =~/^#/); chomp($checkLine); my $found = 0; while (my $tgtLine = <$toFh>) { next if ($tgtLine =~/^#/); # I should't use regular expressions here. my $checkLineQuoted = quotemeta($checkLine); # If $tgtLine has a pattern of $checkLineQuoted. if ($tgtLine =~/$checkLineQuoted/) { $found = 1; last; } } # Perl keeps a position of $toFh even if a while loop ends, so it is necessary to seek the position to the begining of the target file. seek($toFh, 0, 0); if ($notExist) { # Not found string. if ($found == 0) { print "$checkLine\n"; } } else { # Found string. if ($found != 0) { print "$checkLine\n"; } } } close($fromFh); close($toFh);
コメントにも書いたが、このスクリプトのポイントは以下。
seek($toFh, 0, 0);
内側のwhile文で回しているファイルのファイルポインタは、内側のwhile文を抜けて再度内側のwhile文に入った時にリセットされない(先頭まで戻されない)ので、seek関数を使ってファイルポインタを先頭まで戻す必要がある。こうしないと、外側のwhileループの1回目しかちゃんと検索できなくなってしまう。こういうのは言葉で説明しようとするとなかなか難しい。。