序文
によると、ブードゥー教徒らしい dankogai です。 ブードゥー教徒らしく、「上司があなたに金曜夜21時に緊急の仕事を命ずるときにしばしば使われる」呪文をここでまとめておくことにします。
基本中の基本
コマンドとしてのperl
は、スイッチがない場合、引数はスクリプト名として扱われます。
% cat hello.pl
print "Hello, world!\n";
% perl hello.pl
Hello, world!
%
コマンドライン中の文字列をスクリプトとして解釈させるには、-e
を使います。
% perl -e'print "Hello, World!\n"'
Hello, world!
%
ちなみに、perl
とコマンド名だけで起動すると、標準入力をスクリプトとして返します。
% perl
print 1+1, "\n";
[ctrl-D]
2
%
なお、ここまでの挙動はruby
も同じです。
強制改行
Perlには、長らくRubyのputs
相当が不在でした。その代わり、-l
をコマンドライン指定するとprint
がputs
代わりになります。
% perl -e'print "Hello, World!"'
Hello, World! %
% perl -le'print "Hello, World!"'
Hello, World!
%
実は-l
にはprint
を強制改行させるだけではなく、行を強制chomp
する機能もあるのですが、これに関しては後述します。
5.10.0 以降では、say
が加わったので、それを使うことも出来ます。ただし、これをワンライナーから利用するには-e
ではなく-E
を指定する必要があります。
% perl -e'say "Hello, World!"'
String found where operator expected at -e line 1, near "say "Hello, World!""
(Do you need to predeclare say?)
syntax error at -e line 1, near "say "Hello, World!""
Execution of -e aborted due to compilation errors.
% perl -E'say "Hello, World!"'
Hello, World!
-MModuleでモジュールを利用
コマンドラインでモジュールを使うには、-e'use Module; ...'
としてもよいのですが、-MModule
とすることも出来ます。こちらの方が一般的です。
たとえば、以下のワンライナーはhttp://www.dan.co.jp/
の内容を標準出力に書き出します。(もちろんLWPがインストールされていれば)。
% perl -MLWP::Simple -le'print get shift' http://www.dan.co.jp/
-MO=Deparseでスクリプト化
ここで、-MO=Deparse
も覚えておきましょう。perl
にはさまざまなコマンドラインスイッチがあるので、複雑なものを利用した場合、実際に実行されるコードがどうなっているのかわかりにくくなったりしますが、これを使えば「もしコマンドラインではなく、スクリプトだったらどうなるか」を確認することできます。
% perl -MO=Deparse -le'print "Hello, World!"'
BEGIN { $/ = "\n"; $\ = "\n"; }
print 'Hello, World!';
-e syntax OK
%
-n
で一行づつ処理、-p
でそれをprint
ワンライナーの用途で最も多いのが、テキストを一行ずつ処理するというもの。この時使うと便利なのが-n
と-p
。通常どちらも-l
と組み合わせて使います。
例: 行番号を表示
% perl -nle'print "$.:$_"' script.pl
1:while(<>){
2: print "$.:$_"
3:}
find
と組み合わせてperl
を使う時にも、これが大活躍します。詳しくは
もあわせてご覧ください。なお、このオプションはruby
にも受け継がれています。
-iでファイルをまとめて書き換え
ここまでの例では、結果は全て標準出力でしたが、-i
を指定すると、ファイルの出力は入力元となったファイル自身になります。たとえば
% perl -i -ple's/\r\n/\n/g' *.txt
で、DOS式の改行(\r\n
)をすべてUnix式(\n
)に変更できます。
元のファイルを上書きせず残しておきたい場合は、-i.ext
とします。
% perl -i.bak -ple's/\r\n/\n/g' *.txt
とすると、元のファイルは.txt.bak
として残されます。ちなみに-i.bak
の後、
% find . -type f -name \*.bak | perl -nle'$o=$_;s/\.bak$//;rename $o,$_'
とすれば、「アンドゥ」したのと同じことになります。
-aでawkっぽく
-n
または-p
さらに-a
を加えると、AWKっぽい処理も可能になります。ただし、$1
, $2
といった、awk
ではフィールド変数にあたる変数はPerlではregexpで使われているので、フィールドは@F
という配列に格納されます。
例: PIDを列挙する
% ps aux | perl -anle'print $F[1]'
このオプションも、ruby
に移植されています(ruby
の場合は配列オブジェクト$F)。
Unicode使うなら-CIO
Perl 5.8.1から加わったオプションです。Perl 5.8からは、UTF-8を単なるバイト列ではなく文字列としても扱うようになりましたが、下位互換性を保つため、STDIN
やSTDOUT
といった標準ファイルハンドルは、何もしなければバイト列扱いで、これを切り替えるにはbinmode STDIN, ':utf8';
などとしなければなりません。スクリプトならたかだか一行ですが、ワンライナーにはそれでもかったるい。-C
はその悩みを解消します。ちなみにI
は入力を、O
は出力をそれぞれ切り替えます。
口で言うとまだるっこしいのですが、以下を見ればその意味がおわかりいただけるかと。
% perl -MHTML::Entities -ple'$_=encode_entities($_)'
Dan Kogai (小飼弾)
Dan Kogai (小飼弾)
% perl -CIO -MHTML::Entities -ple'$_=encode_entities($_)'
Dan Kogai (小飼弾)
Dan Kogai (小飼弾)
最近の端末エミュレーターは、OS X標準装備のTerminal.app
も含めてUTF-8にはじめから対応しているものが多いので、日本語処理もワンライナーでやりやすくなりました。ぜひ活用してみましょう。
まとめ
このようにワンライナーに強いのがperl
の美点の一つです。私のshellのhistoryには、こうして出来たone-linerがどっさりたまっています。
% echo $SHELL
/bin/tcsh
% echo histdup
erase
% echo $savehist
1024
% history | perl -nle'/perl/ and $p++;END{print $p}'
257
なんと1/4がワンライナーでした。みなさんも是非。
そうそう。次はid:malaにてお願いします。
Dan the One-Liner Monger
See Also: