2006 年 3 月 31 日 21 時 41 分

shebang の解析と実行


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


shebang の行かどうかは、
先頭が#! で開始しているかどうかを調べればいい。

if "%SHEBANG:~0,2%" == "#!" echo SHEBANG!

ただ、一昨日のプログラムでは、
for によって特殊変数に行を読み込んでいたため、
そのままでは文字列の部分比較ができない。
そのため、一度普通の変数に格納する必要がある。

set SHEBANG=%s

#! を取り除いたものが、処理系のコマンドだ。
/usr/local/bin/perl -w とかが入る。
先頭から 0 ベースで 2 番目以降の文字を抜き出せば OK。

set HANDLER=%SHEBANG:~2%

さて、最後に Windows ならではの処理をしておこう。
Windows にはドライブの概念がある。

ハンドラがパスを含めずに書いてあれば、
Windows も PATH を探すので問題ないが、
ドライブを含まない絶対パスの場合に困る。
Shebang を含むファイルは大抵そうだ。

なので、絶対パスであり、かつドライブが含まれない場合、
スクリプトのドライブとみなすことにしよう。

バッチファイルの引数でスクリプトのファイルが渡るので、
%1 という特殊変数で引数のファイル名を得ることができる。
それに対して、ドライブのみ展開する記法を使えばいい。

if "%HANDLER:~0,1%"=="/" set HANDLER=%~d1%HANDLER%

後は引数をつけて実行するだけだ。

%HANDLER% %*

よし、バッチファイルにしてみよう。

========== shebang.cmd ==========
@echo off

for /f "usebackq delims= eol=" %%s in ("%~1") do (

    rem # 行を変数 SHEBANG に格納する。
    set SHEBANG=%%s

    rem # 一行目だけでいいので繰り返さずに抜ける。
    goto break;
)
:break

rem #! で始まるかどうか調べる。
if not "%SHEBANG:~0,2%"=="#!" (

    rem # ファイルが見つからない、または
    rem # shebang が見つからない場合、シェルにお任せ。
    rem # %* は渡されたコマンドライン全体だ。
    %*

    rem # :eof はファイルの最後を意味する特殊なラベル。
    goto :eof
)

rem # ハンドラ(処理系)のパスや引数を切り出す。
set HANDLER=%SHEBANG:~2%

rem # 絶対パスであり、かつドライブが含まれない場合、
rem # スクリプトのドライブとみなす。
if "%HANDLER:~0,1%"=="/" set HANDLER=%~d1%HANDLER%

rem # ハンドラに引数を渡して実行。
%HANDLER% %*

========== end of shebang.cmd ==========


よし、できた。テストのためのファイルを作ろう。
良くある perl スクリプト。


========== test.cgi ==========
#!/usr/local/bin/perl

print "Hello World!\n"
========== end of test.cgi ==========


へぼっ。仕方ないか。
C:\usr\local\bin\perl.exe は用意しておくこと。
Windows では ActivePerl かな。

んでもって、Windows っぽいのを。
netsh 使って、dns の設定を表示する。
netsh も、# がコメントなので使える。
netsh は、-f オプションを使ってスクリプトを実行する。

========== test.nsh ==========
#!netsh -f

interface ip show dns
========== end of test.cgi ==========


実行してみる。

c:\>shebang test.cgi
Hello World!

c:\>shebang test.nsh

Configuration for interface "Wireless Network Connection"
    DNS servers configured through DHCP:  192.168.0.1
    Register with which suffix:          None

Configuration for interface "Local Area Connection"
    DNS servers configured through DHCP:  192.168.0.1
    Register with which suffix:          None


いい感じ。

shebang.cmd を !.cmd などに変えて、
パスの通った場所に置いておけば、

! test.nsh

の様に実行できる。だからどうしたって感じだが。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.