なぜ"#!/bin/sh -" shebangに "-"があるのですか?

なぜ
#! /空/sh -

(または少なくとも)しばしば推奨されますシェルボーンスクリプトを/bin/sh(または#! /bin/bash -bash、#! /bin/ksh -kshなど)として解釈するようにします。

なぜちょうど#! /bin/shまたは#!/bin/sh

それは何ですか-

ベストアンサー1

これは、次のように書く必要がある理由と似ています。

rm -- *.txt

まさか

rm *.txt

.txt現在のディレクトリに名前があります-

存在する:

RM<パラメータ>

<arg>ファイルで始まる場合は-オプションと見なされ、それ以外の場合は削除するファイルと見なされます。存在する

RM-<パラメータ>

<arg>ファイルの起動にかかわらず、常に削除の対象と見なされます-

についても同様ですsh

実行時

#! /bin/sh

一般的には以下に関連しています。

execve("path/to/the-script", ["the-script", "arg"], [environ])

システムはそれを次に変換します。

execve("/bin/sh", ["/bin/sh", "path/to/the-script", "arg"], [environ])

これpath/to/the-script通常、スクリプト作成者の制御を受けません。作成者は、スクリプトのコピーがどこに保存されるのか、どの名前で保存されるのかを予測することはできません。特に、保証することはできません。path/to/the-script呼び出しが開始されない場合-(または+問題である可能性があるsh)ので、必要これ-でオプションが終了しました。

たとえば、私のシステムにはzcat(実際に他のほとんどのスクリプトと同様に)そのアドバイスに従わないスクリプトの例があります。

$ head -n1 /bin/zcat
#!/bin/sh
$ mkdir +
$ ln -s /bin/zcat +/
$ +/zcat
/bin/sh: +/: invalid option
[...]

#! /bin/sh -今、なぜそうではないのかと尋ねることができます#! /bin/sh --

#! /bin/sh --POSIXシェルで使用できますが、特に#! /bin/sh -古代バージョンは古いバージョンshと見なされsh、オプションの終了を長時間表示するために使用されます。 Bourneシェル(70年代後半から)が引数を解析する方法で、最初の引数がで始まると、その後のすべての文字はオプション名として扱われます。これが止まり、Bourneのようなすべての後続のシェルはそれをオプションの終わりを示す方法として扱いました。-getopt()------

Bourneシェル(現代のBourneに似たシェルではない)は#! /bin/sh -euこの問題を解決することもできます。オプションは最初の引数のみを考慮するためです。

さて、何人かの人々は私達がここで賢いと言うかもしれません。これが私がこの記事を書く理由です。必要上記のイタリック体:

  1. 正しい考えを持っている人は、または-で始まるスクリプトを呼び出すか、名前がまたは+で始まるディレクトリにスクリプトを配置しません。-+
  2. そうであったとしても、最初の人は自分が責任を負う必要があり、スクリプトを呼び出すときに通常シェルまたはexecvp()/execlp()型関数で発生すると主張します。この場合、通常は呼び出して見つけることができますthe-script$PATHこの場合、システムコールへのパス引数は通常(notまたは)execve()で始まるか、現在のディレクトリで実行したいのと同じです(その後、パスはis notで始まります)。/-+./the-scriptthe-script./-+

今は理論に加えて断定#! /bin/sh -質問、推薦する別の理由があります良い練習。これは、いくつかのシステムがまだsetuidスクリプトをサポートしていた時代にさかのぼります。

以下を含むスクリプトがある場合:

#! /bin/sh
/bin/echo "I'm running as root"

スクリプトは-r-sr-xr-x root bin権限と同様に setuid ルートであり、通常のユーザーが実行する場合、これらのシステムでは

execve("/bin/sh", ["/bin/sh", "path/to/the-script"], [environ])

完了ですroot

ユーザーがシンボリックリンクを作成し/tmp/-i -> path/to/the-scriptて実行すると、対話型シェル()が-i始まります。/bin/sh -iroot

この問題を解決でき-ます(解決できません競争条件の問題、またはいくつかのsh実装(例: - ベースの実装はinなしでスクリプトパラメータを探しますksh88)。/$PATH

最近では、setuidスクリプトをサポートしていないシステムはほとんどなく、まだ実行している一部のシステム(通常はデフォルトではありません)は、この問題とコンテスト条件を解決するためにスクリプトを読み取るためにファイル記述子を開く作業を実行しますexecve("/bin/sh", ["/bin/sh", "/dev/fd/<n>", arg])<n>

Bourneのようなシェルだけでなく、ほとんどのインタプリタでも同様の問題が発生します。 Bourneに似ていないシェルは通常、オプションの終わりの-表示をサポートしていませんが、通常はサポートしています--(少なくとも最新バージョンでは)。

返品

#! /usr/bin/awk -f
#! /usr/bin/sed -f

問題ありません。いずれにせよ、次の引数はオプションの引数と見なされますが、そうであればまだ-f機能しません(この場合、ほとんどの/実装では/はファイルから出るのではなく、標準から来ます)。入力する)。path/to/script-sedawksedawk-

また、ほとんどのシステムでは以下を使用できません。

#! /usr/bin/env sh -
#! /usr/bin/perl -w --

ほとんどのシステムと同様に、shebangメカニズムは次のもののみを受け入れます。一つインタプリタパスの後に続くパラメータです。

#! /bin/sh -VSを使用する#!/bin/sh -かどうかは、味の問題です。私はインタプリタパスをより明確にし、マウスの選択をより簡単にするので、前者を好みます。一つある伝説によると、一部の古代バージョンのUnixにはこのスペースが必要でした。しかし、私が知っている限り、これは確認されたことがありません。

Unix shebangに関する非常に良い参考資料は以下にあります。https://www.in-ulm.de/~mascheck/various/shebang


1使用しても追加の操作をzsh実行でき、オプションの終わりを表示することもできます。#! /bin/zsh -eu--

おすすめ記事