みなさん!Perlつかってますか!
ぼくは日常的に使ってます。
さて、PerlはCPANモジュールを駆使して適切な設計さえ行えば、大規模なWebアプリも構築できるほどパワフルな言語ではありますが、その本領はやはりコマンドラインツールやスクリプトとしての使われ方でしょう。
今回はコマンドラインツールとしてのperl
の使い方を簡単に紹介します。
コマンドラインツール
多くのコマンドラインツールにはGNU系とBSD系の異なる実装が存在します。
たとえば、文字列置換によく使うsed
はBSD系とGNU系でちょっとオプションが異なったりしますよね。
perl
はsed
やgrep
の代替としても使うことができるわけですが、perl
でそれら代替する最大の利点はOSが異なっても同じインターフェイスで扱えることでしょう。
一度覚えて手癖にしてしまえば急場でもOSの違いを気にせずにサッとログをまとめたりCSVなどを処理したりできるわけです。便利でしょー。
簡単にsed
やgrep
をどのように代替することができるのかを見ていきます。
sedの代替
sed
にpipeされた入力をFoo
からBar
に置換するにはたとえばこのようにすれば良いでしょう。
... | sed -e 's/Foo/Bar/g'
perl
で代替するとこうなります。
... | perl -pe 's/Foo/Bar/g'
ほぼ変わらないですね!
perl -pe
で sed -e
の代わりとして使うことが出来ます。
もちろん、ファイルを置換してバックアップをつくる -i
オプションも同様に使うことが出来ます。簡単ですね!
原理
これがどのように動いているのかを簡単に解説します。
-e
オプションは続く引数をコードとして解釈するものです。
-p
オプションはコードを以下のように展開して実行するモードになります。(-MO=Deparse
を付けて実行するとどのようなコードが実行されるのかよくわかります。)
LINE: while (defined($_ = readline ARGV)) {
s/Foo/Bar/g;
}
continue {
die "-p destination: $!\n" unless print $_;
}
ARGV
という特殊なファイルハンドルを読むことで、引数または標準入力を$_
に読んでからコードを実行することになります。
このとき、 s/Foo/Bar/g
はそのマッチ対象が指定されていないため $_
を対象に動作し、continue
ブロックのprint $_
で出力されるというカラクリになっています。
詳しくはARGVなどについてのドキュメントを参照するとよいでしょう:
grepの代替
grep
にpipeされた入力からFoo
を含むものだけに絞るにはたとえばこのようにすれば良いでしょう。
... | grep 'Foo'
perl
で代替するとこうなります。
... | perl -ne 'print if /Foo/'
ちょっとコードっぽくなりましたが、分かりやすいかとおもいます。
perl -ne
で grep
の代わりとして使うことが出来ます。
当然ながら、Perlなのでもう少し凝ったマッチをさせることもできます。
たとえば、名前解決をした上で 192.168.
で開始するものを抽出したいとなればこのようにすることでそれができます。
... | perl -MSocket -nle 'print if Socket::inet_ntoa(scalar gethostbyname($_)) =~ /^192\.168\.*/'
また、応用として Foo
を含む行をカウントしたければこのようにするとよいです。
... | perl -nle '$foo++ if /Foo/; END{ print $foo }'
ね、簡単でしょ?
原理
-e
オプションは先程と同じです。
-n
オプションは-p
オプションと似た動きをしますがprint
をしません。
よって perl -ne 'print if /Foo/'
は以下のように展開されます。
LINE: while (defined($_ = readline ARGV)) {
print $_ if /Foo/;
}
まとめ
perl
はsed
などの各種コマンドラインツールを代替できるほか、パワフルなのでちょっと書くだけで様々な処理が行えることを示しました。
これを期に日常の仕事をより豊かにするためにperl
をもっと活用してみては如何でしょうか。
最後にperl
のワンライナーでよく僕が使うdirty hackを紹介して終わりにします。
Foo
を含む行をカウントするワンライナーです。
... | perl -nle '$foo++ if /Foo/}{print $foo'
答え合わせは -MO=Deparse
でどうぞ。