シバンなしファイルでのスクリプト系言語のインタープリターの実行

GNOME Terminal

背景

PHPを勉強しており,PHPの実行方法を調べていた。その中で,シェルスクリプトで実行する方法が目に映った。

いわゆるシバン (shebang, #!) を使った実行方法だ。この方法はその他のスクリプト系言語のインタープリターの指定にも使われており,よく見かけるものだ。ただ,この方法は絶対パスでインタープリターを決め打ちで指定するという点で前からいまいちだと感じていた。

また,インタープリターへの絶対パスを使わない場合は,「Perl, Python 及び Ruby スクリプトにおける正しいshebangの書き方 – Qiita」で説明されている通り,言語独自のオプションや仕様をうまく使って,共通のシバン (#!/bin/sh) を使いうまく方法がある。これはこれで言語ごとに,書き方が異なるし,PHPの場合の事例が記されていない。

絶対パスを使わずに,統一記法で,ファイル名での実行時にスクリプト系言語のインタープリターを起動する方法がないかを考えていた。完璧ではないものの,実現方法が見つかったので記録としてここに記す。

方法

その方法は以下のように1行目を記入することだ。

command -p tail -n +2 "$0" | command -p php ${1+"$@"}; exit $?
<?php
echo "php";

参考: example/interpreter.sh at master · senooken/example

内容は以下の3の手順で構成されている。

手順
  1. tail -n +2 "$0"でファイル内の2行目以降を出力。
  2. ファイル内の2行目以降の出力内容をインタープリターに引き渡して実行。
  3. シェル自体はその後のexit $?により直前のインタープリターのステータスを引き継いで終了。

簡単にいうと,ファイル内の2行目以降をインタープリターに引き渡すことで,1行目の標準シェルからのインタープリターの呼び出しコードをスキップしている。

これにより,シバンを使わずにインタープリターを実行できる。この方法の利点は以下の4点だ。

利点
  1. どのインタープリターでも同じ書き方で対応可能。
  2. /bin/shが存在しないOS (Andorid) でも対応可能。
  3. 2個以上の複雑な引数も引き渡し可能。
  4. 組み込みコマンドのcommand -pにより仮にPATH環境変数が空でも実行可能性上昇。

逆に欠点は以下の2点だ。

欠点
  1. POSIX準拠シェルが存在しないと実行不可能 (標準Windowsでは実行不可能)。
  2. インタープリターでファイルを指定して実行する場合に構文エラー。

特に,欠点の2番目の影響が大きい。1行目はインタープリターの言語と全く無関係の構文のため,インタープリターの引数にファイルを指定して実行すると,確実に1行目でエラーが出る。

これを防ぐには,インタープリターにファイルを指定する際にも,tail -n +2相当の処理をして,常に2行目からファイルの内容を標準入力経由で渡す必要がある。

この欠点のため,この方法はUNIX系OSで常にファイル名での実行のみを想定する場合には有効だ。しかし,主にWindowsのように非UNIX系OSでファイル名でそもそも実行できない,またはインタープリターにファイルを指定して実行したい場合には向いていない。

結論

私見としては,インタープリターが必要なスクリプト系言語での開発では,シバンを付けないほうがよい。シバンという絶対パスを指定する限り,移植性の低下は避けられない。

ファイル名で実行したい場合,パッケージングによりバイナリー形式にして配布したほうがよいだろう。

なお,今回の方法を流用して,「PowerShellを単一.cmdファイルから実行する方法」も掲載した。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です