web-dev-qa-db-ja.com

`#!`構文の動作がPOSIXで指定されていないのはなぜですか?

POSIX仕様の Shell Command Language ページから:

シェルコマンドのファイルの最初の行が文字「#!」で始まる場合、結果は不定です。

なぜ#! POSIXで指定されていませんか?非常に移植性があり広く使用されているものは、不特定の動作をするのではないかと思います。

17
Harold Fischer

主な理由は次のとおりです。

  • 動作は実装によって大きく異なります。詳細は https://www.in-ulm.de/~mascheck/various/Shebang/ を参照してください。

    ただし、ほとんどのUnix風の実装の最小サブセットを指定できるようになりました。たとえば、#! *[^ ]+( +[^ ]+)?\n(1つまたは2つの単語にポータブルファイル名の文字セットの文字のみを使用)で、最初のWordはネイティブ実行可能ファイル、事柄は長すぎず、実行可能ファイルがsetuid/setgidである場合の動作は不特定であり、実装はインタープリターパスまたはスクリプトパスがargv[0]としてインタープリターに渡されるかどうかを定義します。

  • とにかく、POSIXは実行可能ファイルのパスを指定しません。いくつかのシステムでは、/bin//usr/binにPOSIXユーティリティがあり、他の場所にPOSIXユーティリティがあります(Solaris 10では、/bin/shはBourneシェルで、POSIXは/usr/xpg4/binにあります。Solaris11は、POSIX準拠のksh93に置き換えましたが、 /binの他のほとんどのツールは、依然として古代の非POSIXツールです)。一部のシステムはPOSIXシステムではありませんが、POSIXモード/エミュレーションを備えています。 POSIXで必要なことは、システムがPOSIXlyで動作する文書化された環境があることです。

    たとえば、Windows + Cygwinを参照してください。実際、Windows + Cygwinでは、スクリプトがcygwinアプリケーションによって呼び出され、ネイティブのWindowsアプリケーションによって呼び出されない場合、シバンが尊重されます。

    したがって、POSIXがShebangメカニズムを指定した場合でも、POSIX sh/sed/awk...スクリプトを書き込むために使用できませんでした(Shebangメカニズムは使用できないことにも注意してください)オプションの終了マーカーを渡すことができないため、信頼できるsed/awkスクリプトを記述します)。

これが指定されていないという事実は、それを使用できないことを意味するわけではありません(まあ、それが通常のコメントであり、シーバングではない場合は、最初の行を#!で始めるべきではないことを示しています)。しかし、そのPOSIXは保証しません。

私の経験では、shebangsを使用すると、POSIXのシェルスクリプトの記述方法を使用するよりも移植性が保証されます。she-bangを省略して、POSIX sh構文でスクリプトを記述し、スクリプトを呼び出すものすべてがPOSIXを呼び出すことを期待します。それに準拠するsh。スクリプトが適切な環境で適切なツールによって呼び出されることがわかっていて、それ以外の場合は呼び出されない場合は問題ありません。

次のようなことが必要になる場合があります。

#! /bin/sh -
if : ^ false; then : fine, POSIX system by default
else
  # cover Solaris 10 or older. ": ^ false" returns false
  # in the Bourne Shell as ^ is an alias for | there for
  # compatibility with the Thomson Shell.
  PATH=`getconf PATH`:$PATH; export PATH
  exec /usr/xpg4/bin/sh - "$0" ${1+"$@"}
fi
# rest of script

Windows + Cygwinに移植したい場合は、.batまたは.ps1拡張子を使用してファイルに名前を付け、cmd.exeまたはpowershell.exeに同様のトリックを使用して、同じファイルでcygwin shを呼び出す必要があります。

21

[T]彼の動作は、すべてのPOSIX準拠シェル間で一貫しているようです。ここに小刻みに部屋を置く必要はないと思います。

あなたは十分に深く見ていない。

1980年代に戻ると、このメカニズムは事実上標準化されていません。デニス・リッチーはそれを実装しましたが、その実装は宇宙のAT&T側では一般に公開されていませんでした。これは事実上、一般にのみ入手可能で、BSDで知られていました。 AT&T Unixでは使用できない実行可能なシェルスクリプトしたがって、標準化することは合理的ではありませんでした。現状は、この現代的なドコによって例示されています。

BSDでは_#! interpreter_で始まるファイルを直接実行できますが、SysVではa.outファイルのみを直接実行できます。つまり、BSDプログラムのexec…()ルーチンの1つのインスタンスを、代わりにそのプログラムのインタープリター(通常は_/bin/sh_)を実行するためにSysVで変更する必要がある場合があります。
— Stephen Frede(1988)。 「システムXリリースYでのプログラミング」。 オーストラリアのUnixシステムユーザーグループニュースレター。ボリューム9。番号4。 111。

ここで重要な点は、シェルを見ているということですが、実行可能なシェルスクリプトの存在は、実際にはexec…()関数の問題です。シェルが行うことには、実行可能なスクリプトメカニズムのprecursorsが含まれますが、現在でも一部のシェルで見られます(また、今日ではexec…p()サブセットの関数が義務付けられています) 、やや誤解を招く可能性があります。この点に関して規格が対処する必要があるのは、解釈されたスクリプトのexec…()がどのように機能するかであり、POSIXが最初に作成されたとき、最初から最初は機能しませんでした。ターゲットオペレーティングシステムのスペクトルの主要部分

下位の質問は、なぜこれが標準化されていないのか、特にスクリプトインタープリターのマジックナンバーメカニズムhadが宇宙のAT&T側で一般に公開され、exec…()System 5 Interface Definitionで、1990年代の終わりまでに:

インタープリターファイルは、という形式の行で始まります。
#!パス名[arg]
ここで、pathnameはインタープリターのパスであり、argはオプションの引数です。インタープリターファイルをexecすると、システムは指定されたインタープリターをexecsします。
execSystem Vインターフェイス定義。ボリューム1. 1991。

残念なことに、この行動は今日でも1980年代とほぼ同じように広がっており、標準化する真に一般的な行動はありません。一部のUnices(有名にはHP-UXやFreeBSDなど)は、スクリプトのインタープリターとしてのスクリプトをサポートしていません。最初の行が1つ、2つ、または空白で区切られた多くの要素であるかどうかは、MacOS(および2005より前のバージョンのFreeBSD)とその他の間で異なります。サポートされる最大パス長は異なります。 __およびPOSIXポータブルファイル名の文字セット以外の文字は、先頭および末尾の空白と同様に扱いにくいものです。第0、第1、および第2の引数が最終的に何であるかは、システムによって大幅に異なるため、注意が必要です。現在いくつかのPOSIX準拠ですが、non-Unixシステムはまだそのようなメカニズムをサポートしておらず、強制すると、POSIX準拠ではなくなります。

参考文献

9
JdeBP

他のいくつかの回答で述べたように、実装はさまざまです。これにより、既存のスクリプトとの下位互換性を維持およびすることが困難になります。これは、最新のPOSIXシステムにも当てはまります。たとえば、Linuxはシバン行をスペースで完全にトークン化しません。 macOSでは、スクリプトインタープリターを別のスクリプトにすることはできません。

http://en.wikipedia.org/wiki/Shebang_(Unix)#Portability も参照してください

1
jamesdlin