WinでActive Perlを使う際の、以前から気になっていた話
例えば test.pl
が
#!/usr/bin/perl while (<>) { s/hoge/moe/g; print; }
となっていて、DOSプロンプトから
>test.pl hogehoge ^Z
とやってやった((以下、あらかじめ拡張子が.pl
のファイルを実行ファイルとして扱うようにWin側で設定はしてあるものとする。))ときは応答は当然 moemoe
になるけれども、
>echo hogehoge | test.pl
とやってやったとき、同じく moemoe
が返って来ると思いきや応答は空になる。どうやらtest.pl
はコマンドラインから実行してやった際にパイプから何も読み込まないらしい。何でだろう。一方で
>echo hogehoge | perl test.pl
とやってやった場合には普通に moemoe
を返す。
DOSプロンプトでちょこちょことフィルタなど書いてやっても、使うときにいちいち頭に perl
とか打たされるのは面倒だし第一納得行かない(笑)。何とかならないかしらと思っていたら、Active Perl のディレクトリに面白いサンプルを見つけた。拡張子は .bat
になっていて、ファイルの頭に以下のように書いてある:
@rem = '--*-Perl-*-- @echo off if "%OS%" == "Windows_NT" goto WinNT perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9 goto endofperl :WinNT perl -x -S %0 %* if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofperl if %errorlevel% == 9009 echo You do not have Perl in your PATH. if errorlevel 1 goto script_failed_so_exit_with_non_zero_val 2>nul goto endofperl @rem '; #!perl (ここに普通のPerlのコードが入る) __END__ :endofperl
自分自身を改めてPerlに食わせてやっている。-x
オプションつきで呼ばれるとPerlの処理系は #!perl
行までを読み飛ばすのだそうな。結果的にPerlのスクリプトとして読み込まれたときには #!perl
行から __END__
プラグマまでの間だけが実行され、一方で最初にDOSのバッチファイルとして呼ばれたときにはPerlのコードの部分は goto
文でスキップするという仕掛けで両者が同一ファイル中に共存しているらしい。
注意すべきことを一つ。上の要領で書いたPerlのスクリプト部分がエラーを出した場合、エラー行の行番号は #!perl
行を1行目としてカウントする。つまり冒頭のバッチ部はカウントされない。
もう一つ面白い点。上の例で冒頭のバッチ部にコメント行 (@rem
文)が2つあるが、これのおかげでバッチ部全体がPerlのコードとして見た時にはリスト @rem
への代入文の体裁になるようにしてある。Perlに読ませてやった時にはここは実行しない筈なのに何でわざわざこんなことをしているのかイマイチ謎。念の為、上の例のPerl部に print "@rem";
とか書いて保存・実行してやると答えは空。もしかしたらこれ、うっかり
>perl test2.bat
とかしてやったときに冒頭のバッチ部がエラーを出さないようにしてあるだけ?