#!/ bin / sh-
によって解釈されるスクリプトを使用することが推奨されるシバンです(または少なくともそうでした)/bin/sh
。
なぜだけでは#! /bin/sh
ないの#!/bin/sh
ですか?
それは何の-
ためですか?
#!/ bin / sh-
によって解釈されるスクリプトを使用することが推奨されるシバンです(または少なくともそうでした)/bin/sh
。
なぜだけでは#! /bin/sh
ないの#!/bin/sh
ですか?
それは何の-
ためですか?
回答:
それはあなたが書く必要がある理由と同じ理由です:
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
前日-
として処理し、長い間オプションの終了をマークするgetopt()
ための一般的な使用--
。Bourneシェル(70年代後半以降)が引数を解析する方法で、最初の引数のみがで始まる場合にオプションとして考慮されました-
。以降のすべての文字-
はオプション名として扱われます。の後に文字がない場合-
、オプションはありません。それは止まり、後のすべてのBourne風のシェル-
はオプションの終わりをマークする方法として認識します。
Bourneシェル(ただし、現代のBourneのようなシェルではない)では、#! /bin/sh -euf
オプションの最初の引数のみが考慮されたため、問題を回避できます。
ここで、私たちはここで行していると言うことができます。 上記の斜体で必要性あります:
-
か、+
または名前がで始まるディレクトリに入れ-
たり+
。execvp()
/ execlp()
型関数からです。そして、その場合には、一般的に、あなたは、のいずれかとして、それらを呼び出すthe-script
ことがでルックアップさせるため$PATH
にケース内パス引数execve()
のシステムコール、一般的に開始します/
(ない-
も+
)またはとして./the-script
あなたがしたい場合はthe-script
(カレントディレクトリで実行すると、その場合、パスはで始まらず、どちらでもあり./
ませ-
ん+
)。理論的な正確性の問題に加えて、グッドプラクティス#! /bin/sh -
として推奨されるようになったもう1つの理由があります。そして、それはいくつかのシステムがまだsetuidスクリプトをサポートしていた時代にさかのぼります。
次を含むスクリプトがある場合:
#! /bin/sh
/bin/echo "I'm running as root"
そして、そのスクリプトは-r-sr-xr-x root bin
、通常のユーザーによって実行された場合、それらのシステム上でsetuid root(パーミッション付きなど)でした。
execve("/bin/sh", ["/bin/sh", "path/to/the-script"], [environ])
として行われroot
ます!
ユーザーがシンボリックリンク/tmp/-i -> path/to/the-script
を作成してそれを実行した場合-i
、対話型シェル(/bin/sh -i
)を起動しroot
ます。
これ-
は回避できます(競合状態の問題や、一部のsh
実装のような一部の実装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
で-
と、その場合には(ほとんどのsed
/ awk
実装、sed
/awk
からのコードを読んでいません-
ファイル、しかし代わりに標準入力から)。
また、ほとんどのシステムでは以下を使用できないことに注意してください。
#! /usr/bin/env sh -
#! /usr/bin/perl -w --
ほとんどのシステムと同様に、シバンメカニズムでは、インタープリターパスの後に引数を1つだけ許可します。
#! /bin/sh -
vs を使用するかどうかは#!/bin/sh -
、単に好みの問題です。前者のほうが、インタープリターパスがより見やすくなり、マウスの選択が容易になるためです。一部の古代のUnixバージョンではスペースが必要だったという伝説がありますが、これは確認されていないためです。
Unixシバングに関する非常に良いリファレンスは、https: //www.in-ulm.de/~mascheck/various/shebangにあります。
bash
他のすべてのシェルと同様にオプションを受け入れます。BourneのようなPOSIXシェルであるため、とのbash
両方#! /bin/bash -
を受け入れます#! /bin/bash --
。