sjisのファイルを直接grepしたかったから練習がてらperlで書いてみた
自分の要望として
- sjisのファイルをコマンドラインからgrepしたい
- 複数ファイルにまたがってgrepしたい
- 検索結果にファイル名と行番号を表示したい
- catでつないでnkf -wってすればできるけど、どのファイルかわからなくなる
練習のつもりでperlで書いてみたらすごい時間かかった。一行書くごとにググってた気がする。
ソース
もとからあるコマンドを組合せればできるのかもだけど、きっとすぐ忘れるからperlでそんな処理を書いてみた。書きかたとしてあってるのかは知らない。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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; | |
} |
~/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するとファイル名のみが表示される。
@_の最初の要素が$_ってわけではない?
やっぱりちゃんと基礎から勉強しないといけない気がする。