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


17

POSIX仕様のシェルコマンド言語ページから:

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

#!POSIXで動作が指定されていないのはなぜですか?移植性が高く、広く使用されているものが不特定の動作をすることには困惑させられます。


1
規格では、実装を特定の動作に拘束しないように、指定されていないものを残しています。たとえば、「ログイン」は「ユーザーがシステムにアクセスするための不特定のアクティビティ」です。
クサラナナンダ

2
POSIXは実行可能なパスを指定しないため、シバン行は本質的に移植性がありません。とにかくそれを指定することで多くが得られるかどうかはわかりません。
マイケル・ホーマー

1
@MichaelHomer、確かではない?標準では、そのパスが何であるかを指定しなくても、インタープリターに使用するパスが行に含まれることを指定できます。
ilkkachu

1
@HaroldFischerシェルによって解釈されない場合を除き、OSカーネル(少なくともLinuxでは実行され、ビルド時にこのサポートを実際に無効にできる)、またはexec()関数を実装するライブラリによって解釈されます。したがって、複数のシェルをチェックしても、それがどれほど移植性があるかはわかりません。
オースティンヘメルガーン

2
@HaroldFischerさらに、POSIX準拠のOSの間でも、動作に一貫性がありません。LinuxとmacOSの動作は異なります。Linuxはスペースによってシバン行を完全にトークン化するわけではありません。macOSでは、スクリプトインタープリターを別のスクリプトにすることはできません。en.wikipedia.org/wiki/Shebang_(Unix)#Portability
jamesdlin

回答:


21

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

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

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

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

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

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

今、それが指定されていないという事実は、あなたがそれを使用できないことを意味しません(まあ、それはあなたがそれが#!通常のコメントであり、シバンではないことを期待するなら、あなたは最初の行を始めてはいけないと言います)が、そのPOSIXを使用しても、保証はありません。

私の経験では、shebangsを使用すると、あなたのシェルスクリプトを書くのPOSIXの方法を使用するよりも、移植の多くの保証を与える:彼女-強打オフ休暇、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.exeCygwinを起動するにはsh、同じファイルに。


興味深いことに、問題5から:「コンストラクト#!は、その拡張機能を提供する実装用に予約されています。ポータブルアプリケーションは、シェルスクリプトの最初の行として#!を使用できません。コメントとして解釈されない場合があります。」
ムル

@muruスクリプトが本当に移植可能で、POSIXを実行しているPOSIXシステム上shで実行されている場合、POSIXによって実行されるので、hashbang行は必要ありませんsh
クサラナナンダ

1
場合のみ、本当@Kusalananda execlpまたはexecvp、右に使用されましたか?を使用するとexecve、ENOEXECになりますか?
ムル

9

[T]この動作は、すべてのPOSIX苦情シェル間で一貫しているようです。私はここで小刻みに動く部屋の必要性を知りません。

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

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

BSDでは、で始まるファイルを#! interpreter直接実行できますが、SysVではa.outファイルのみを直接実行できます。これはexec…()、BSDプログラムのいずれかのルーチンのインスタンスをSysVで変更し/bin/shて、代わりにそのプログラムのインタープリターを(典型的に)実行する必要があることを意味します。
— Stephen Frede(1988)。「System XリリースYでのプログラミング」。オーストラリアUnixシステムユーザーグループニュースレター。9巻。番号4。111。

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

これは、以来、標準化されていない理由を下位問題は、スクリプトインタプリタのためのマジックナンバーメカニズムは、特にとして、あるいた宇宙のAT&T側に公衆に達したとするために文書化されていたexec…()中で、システム5のインタフェース定義、1990年代のターンで、 :

インタプリタファイルは次の形式の行で始まります

#!パス名[引数]
ここで、pathnameはインタープリターのパスであり、argはオプションの引数です。ときにあなたのexecインタプリタファイル、システムexecの指定されたインタプリタを。
execシステムVインターフェース定義。巻1. 1991。

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

参考文献


1

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.