2008年03月30日 19:45 [Edit]

perl - ワンライナーの書き方入門

camel

まあ、ruby のコマンドラインオプションって、Perl由来ですから。

Rubyでワンライナーを書く方法のまとめ
まぁ、Perlもあるしあんまり需要が無いのかも知れませんが。

というわけで、Rubyistにも役立つPerlのワンライナー入門です。


基本中の基本

コマンドとしての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をコマンドライン指定するとprintputs代わりになります。

% 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 . -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を単なるバイト列ではなく文字列としても扱うようになりましたが、下位互換性を保つため、STDINSTDOUTといった標準ファイルハンドルは、何もしなければバイト列扱いで、これを切り替えるにはbinmode STDIN, ':utf8';などとしなければなりません。スクリプトならたかだか一行ですが、ワンライナーにはそれでもかったるい。-Cはその悩みを解消します。ちなみにIは入力を、Oは出力をそれぞれ切り替えます。

口で言うとまだるっこしいのですが、以下を見ればその意味がおわかりいただけるかと。

% perl -MHTML::Entities -ple '$_=encode_entities($_)'
Dan Kogai (小飼弾)
Dan Kogai (小é£&frac14;å&frac14;&frac34;)
% perl -CIO -MHTML::Entities -ple '$_=encode_entities($_)'
Dan Kogai (小飼弾)
Dan Kogai (&#x5C0F;&#x98FC;&#x5F3E;)

最近の端末エミュレーターは、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がワンライナーでした。みなさんも是非。

Dan the One-Liner Monger

See Also:

この記事へのトラックバックURL

この記事へのトラックバック
perl-users.jpで、 JPerl Advent Calendar 2008 という「駅伝エッセイ」が進行中です。
perl - JPerl Advent Calendar 2008【404 Blog Not Found】at 2008年12月22日 12:47
「JavaScript & DHTMLクックブック 第2版」と一緒に献本頂いたのが、こちら。 ミニマルPerl Tim Maher / 安藤慶一&amp; 磯部孝一郎訳 [原著:Minimal Perl] ああ、癒される。 ♪grepで追いし かのlog ♪sedで直し かのsource ♪Unixは今もめぐりて ♪離...
ふるさと再訪 - 書評 - ミニマルPerl【404 Blog Not Found】at 2008年06月17日 19:03
この記事へのコメント
改行コードの変換を意図したワンライナーで -l オプションをつけてしまうと、期待通りに動作しないのではないでしょうか。

% perl -i -ple 's/\r\n/\n/g' *.txt
ではなく、

% perl -i -pe 's/\r\n/\n/g' *.txt
とするのが正しいように思います。
Posted by ktgy1016 at 2011年08月04日 00:46
15年くらい前にPerlがいいって聞いたけど、AWKで満足してた自分はずっとAWK使い。
愛用のHP200LXで使えるのが、それしかないってこともあるけど。
シンプルなスクリプトでねらい通りに処理できたときは快感ですね。
Posted by おおくは望まない? at 2008年03月31日 15:02
s/printをputs/printがputs/

重箱の隅ですが・・
Posted by 初学者K at 2008年03月31日 14:58
ワンライナーは昔「一行野郎」なんていう言い方もしてましたね。この言い方が結構好きだったんですが今ではあまり聞かなくなってしまいました。
Posted by Sio @ Sio's Gadget Blog at 2008年03月30日 21:43