Skip to main content
  1. Entry/

sjisのファイルを直接grepしたかったから練習がてらperlで書いてみた

自分の要望として

  1. sjisのファイルをコマンドラインからgrepしたい
  2. 複数ファイルにまたがってgrepしたい
  3. 検索結果にファイル名と行番号を表示したい
    • catでつないでnkf -wってすればできるけど、どのファイルかわからなくなる


練習のつもりでperlで書いてみたらすごい時間かかった。一行書くごとにググってた気がする。

ソース

もとからあるコマンドを組合せればできるのかもだけど、きっとすぐ忘れるからperlでそんな処理を書いてみた。書きかたとしてあってるのかは知らない。

#!/usr/bin/env perl
use strict;
use warnings;
use Encode;
use File::Find;
use Term::ANSIColor::Print;
my @targets = split /,/, $ARGV[0];
my $dir = $ARGV[1] || '.';
my $print = Term::ANSIColor::Print->new;
find \&wanted, ($dir);
sub is_file {
return -f $_;
}
sub search {
my ($line, $linum) = @_;
Encode::from_to($line, 'sjis', 'utf8');
$line =~ s/\n//;
for my $target (@targets) {
unless ($line =~ /$target/) {
return '';
}
}
return "$linum: $line\n";
}
sub process {
my @path = @_;
my $file = $_;
return unless is_file $file;
my $fh;
my ($line, $linum, $result);
open $fh, '<', $file;
$linum = 0;
while ($line = <$fh>) {
$result .= search $line, ++$linum;
}
if (length $result) {
$print->green(@path);
print $result;
print "\n";
}
close $fh;
}
sub wanted {
process $File::Find::name;
}
view raw sgrep.pl hosted with ❤ by GitHub

~/bin/sgrep とかに実行権限付けて置いといて使ってる。
名前がgrepだけど、そんなだいそれた機能は無いです。
「検索っていったらgrepじゃない?」と思って安易に付けただけです。

使いかた?

たとえば、

$ sgrep 'hoge'

とすればhogeが含まれる行の一覧をカレントディレクトリ以下すべてのファイルを対象に正規表現で検索する。

第二引数にディレクトリ名を与えれば、そのディレクトリ以下のファイルを対象に検索する。

$ sgrep 'hoge' dirname

キーワードをカンマでつなぐとAND検索される。

$ sgrep 'hoge,huga'
# => hogeとhugaを含む行を表示

課題

  • コマンドのヘルプってどうやって書くの?
  • エラー処理とかなくていいの?
  • 処理速度とかどうなの?
  • sjisじゃないファイルに使うときっと文字化けする

疑問

wantedの中でopenしたらうまくいかなかった。
サブルーチンにわけたらうまくいった。
なして?

なんだか無駄そうなis_fileも同じ理由。
unlessのあとに直接-f $fileとしたら必ず偽になった。
なして?

processの頭の@_と$_。
@_をprintするとカレントディレクトリからの相対パスが、
$_をprintするとファイル名のみが表示される。
@_の最初の要素が$_ってわけではない?

やっぱりちゃんと基礎から勉強しないといけない気がする。