LoginSignup
49
36

More than 5 years have passed since last update.

コマンドラインツールとしてのperl

Last updated at Posted at 2017-12-18

みなさん!Perlつかってますか!
ぼくは日常的に使ってます。

さて、PerlはCPANモジュールを駆使して適切な設計さえ行えば、大規模なWebアプリも構築できるほどパワフルな言語ではありますが、その本領はやはりコマンドラインツールやスクリプトとしての使われ方でしょう。
今回はコマンドラインツールとしてのperlの使い方を簡単に紹介します。

コマンドラインツール

多くのコマンドラインツールにはGNU系とBSD系の異なる実装が存在します。
たとえば、文字列置換によく使うsedはBSD系とGNU系でちょっとオプションが異なったりしますよね。
perlsedgrepの代替としても使うことができるわけですが、perlでそれら代替する最大の利点はOSが異なっても同じインターフェイスで扱えることでしょう。
一度覚えて手癖にしてしまえば急場でもOSの違いを気にせずにサッとログをまとめたりCSVなどを処理したりできるわけです。便利でしょー。
簡単にsedgrepをどのように代替することができるのかを見ていきます。

sedの代替

sedにpipeされた入力をFooからBarに置換するにはたとえばこのようにすれば良いでしょう。

... | sed -e 's/Foo/Bar/g'

perlで代替するとこうなります。

... | perl -pe 's/Foo/Bar/g'

ほぼ変わらないですね!
perl -pesed -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 -negrep の代わりとして使うことが出来ます。

当然ながら、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/;
}

まとめ

perlsedなどの各種コマンドラインツールを代替できるほか、パワフルなのでちょっと書くだけで様々な処理が行えることを示しました。
これを期に日常の仕事をより豊かにするためにperlをもっと活用してみては如何でしょうか。

最後にperlのワンライナーでよく僕が使うdirty hackを紹介して終わりにします。
Fooを含む行をカウントするワンライナーです。

... | perl -nle '$foo++ if /Foo/}{print $foo'

答え合わせは -MO=Deparse でどうぞ。

49
36
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
49
36