web-dev-qa-db-ja.com

/ bin / bashではなく/ bin / shを指すシバンがある理由はありますか?

私が見たほとんどのシェルスクリプト(自分で記述したものを除く)では、Shebangが#!/bin/shに設定されていることに気付きました。これは、古いスクリプトで私を本当に驚かせることはありませんが、かなり新しいスクリプトでも同じです。

bashは10年以上前に遡る多くのLinuxおよびBSDマシンで広く普及しており、多くの場合デフォルトであるので、/bin/shよりも/bin/bashを選ぶ理由はありますか?

54
Jules
  1. デフォルトでbashを出荷していないシステムがあります(FreeBSDなど)。
  2. Bashがインストールされている場合でも、/binにない場合があります。
  3. ほとんどの単純なスクリプトはbashを必要としません。
  4. POSIXシェルを使用すると移植性が向上し、スクリプトはさまざまなシステムで実行されます。
85
Marco

(Debian関連:Ubuntu、Mintなど)Linuxのほとんどのシステムスクリプトは、高速ダッシュで実行するように記述されています。これは、これらのシステムのデフォルトの/ bin/shです。その理由は2つあります。

  • システムの速度。ダッシュのコードが小さいほど、ロードが速くなり、実行も速くなります。シェルスクリプトのプログラマーにいくつかの(小さな?)追加の労力(コスト)がかかります。

  • セキュリティ。シェルの多様性は、バグへの回復力を高めます。デフォルトのシェルにはそのような脆弱性がなかったため、DebianシステムはほとんどShellshockに対して脆弱ではありませんでした。

Bashは確かにsersのデフォルトのシェルです。これは、より強力で、コーディングを容易にするための要素がはるかに多いためです。これは、Mac OSのデフォルトのshでもあります(/ bin/shからリンクされているもの)。ただし、bashというリンク名でshを呼び出すと、posix準拠のシェルとして起動します。

28
user79743

他の人たちは、ボーンアゲインシェルがデフォルトであり、ユビキタスであるという質問の前提はまったく間違っていると指摘しました。

それに加えて、シェルスクリプトの解釈にBourne Againシェル以外のものを使用することには、確かに十分な理由があります。これらの理由により、何年にもわたってUbuntuとDebianの大きなプロジェクトが動機づけられ、バシズムを取り除き、システムの初期化によってシェルスクリプトを実行するようになりました(これはシェルのロットでした) System 5 rc)およびパッケージのインストール/削除を使用したスクリプトは、Bourne Againシェルの代わりにDebian Almquistシェルを使用します。

簡単に言うと、Bourne Again Shellはインタラクティブな機能がそのまま満載されているため、POSIX準拠のShellスクリプトの最速のシェルインタープリターではありません。したがって、シェルスクリプトをPOSIX準拠にして、Debian Almquist Shellのようなより軽量なプログラムで解釈できるようにすると、システムのパフォーマンスが向上します。 (結局、Debianは、Almquistシェルにわずかな調整を加えて、単にあまりにも深く、広く埋め込まれていて、取り除くにはあまりにも有用であるいくつかの非POSIXシェル構成のサポートを追加する必要がありました。)

すべての結果、bootstrapパフォーマンスが大幅に向上しました。

したがって、考慮すべきシェルには2つの異なるクラスがあります。

  • 派手なインタラクティブ機能をすべて備えたシェル。アカウントデータベースのユーザー用のインタラクティブログインシェルとして構成されています。
  • シェルスクリプトプログラムによってスクリプトインタープリターとして使用される、多くのスクリプトをすばやく解釈するシェル。

これを「/bin/shを優先する」として説明するのは簡単すぎることに注意してください。 Debianには実際には少なくとも2つの目標がありました。

  1. Debian Almquistシェル、Zシェル(POSIXモード)、Bourne Againシェル(POSIXモード)、MirBSD Kornシェル、その他を/bin/shとして使用している管理者に直面して、…

    1. …スクリプトを可能な限り移植可能にすることで、/bin/shのマッピング先を切り替えても問題は発生しませんでした。または

    2. …移植性のないスクリプトを明示的に対象とする正しいインタプリタプログラムにする代わりに、単に/bin/shがそれにマップすることを期待するのではありません。

  2. Debian AlmquistシェルをBourneシェルではなく/bin/shのデフォルトマッピングにしていたため、これらのスクリプトはPOSIX準拠(より正確には、Debianポリシーマニュアル準拠)でしたより速く走った。

そしてもちろん、これに取り掛かると、さらに多くのことを実行できます。たとえば、/bin/true/usr/bin/clearなどがシェルスクリプトまたはコンパイルされたプログラムであることの効率のトレードオフを検討します。しかし、幸いにもそれはこの回答の範囲を超えています。 ☺

もちろん、これは非常に新しいものでも、Unix固有のものでもありません。世紀の変わり目の前に、私は「対話型」と「非対話型」の両方のフレーバーを備えたコマンドラインインタープリターを作成して公開し、そのdocoのこの非常に区分を説明し、COMSPECOS2_Shell環境変数の違いに注意しました。同様に、DebianのSystem V rcおよびパッケージのインストール/削除スクリプトでのバシズムの削除に関する議論は、1990年代にさかのぼります。

参考文献

21
JdeBP

/ bin/bashではなく/ bin/shを指すようにする理由はありますか?

はい。 @マルコの優れた答えは、これをよく概説しています。

私のシバンで何を使うべきですか?

独自のスクリプトを作成するときは、テストした最も一般的なことをシバンに指定する必要があります。

私のシステム(Centos 6.6)では、shbashにシンボリックリンクされています。

$ ls -l /bin/sh 
lrwxrwxrwx 1 root root 4 Dec  2  2014 /bin/sh -> bash

つまり、スクリプトにバシムがないことを確認しない限り、シバンでは常に#!/bin/bashを使用します。

Shebangを#!/bin/shに設定することで、shのすべての実装でスクリプトが機能することを約束します。

これは、スクリプトがbashで動作するというよりもはるかに大きな約束です。

次に、システムが使用しているsh実装によっては正しく動作しないスクリプトの例を示します。

#!/bin/sh
n=1
a=$((++n))
echo $n

bashを使用すると、スクリプトは次のように出力します。

2

dashを使用すると、スクリプトは次のように出力します。

1

#!/bin/shを使用したい場合、何をする必要がありますか?

  • checkbashismsを使用してスクリプトを確認します-すべてのバシムが検出されるわけではないことに注意してください。上記のスクリプトでバシズムを見つけられませんでした
  • 別のsh実装を使用してスクリプトをテストします。私は通常dashを使用してテストしますが、一部のバシズムやダシムはまだ抜けることができると思います。

Ubuntu wikiの DashAsBinShページ には、興味深い情報がたくさんあります。

8

より強力で人間工学に基づいた言語でスクリプトを作成する代わりに、シェルスクリプトを作成する唯一の理由は、不明なソフトウェアがインストールされているレガシーシステムへの移植性が他のどの要素よりも重要であるの場合です。

/bin/shは、Unixと呼ばれるすべてのもので利用できる唯一のスクリプトインタープリタです。しかし、非常に多くのレガシーシステムでは、/bin/shおよび関連するユーティリティは、POSIX.1-1996の「シェルとユーティリティ」の仕様にさえ準拠していません。標準準拠のツールは、/usr/xpg4またはそのような自明ではない場所にインストールされるオプションのアドオンです。1 ポータブルサブセットシェル言語へのスクリプトは、POSIXシェル言語へのスクリプトよりも面倒でエラーが発生しやすくなります。 (あなたが私を信じていない場合は、いつかAutoconfが生成したconfigureスクリプトを読んでください。あなたを納得させるには、設定だけで十分です。)

ただし、他のスクリプトインタープリターがインストールされていると想定できる場合(例:Bash)、のインタープリターを想定できます。より良いスクリプト言語がインストールされています。たとえば、PerlはBashよりもmoreが利用できる可能性が高くなります。

したがって、never#! /bin/bashスクリプトを記述してください。これがオプションである場合、より優れた言語もオプションです。

1 たとえば、Solaris 10以前では、オリジナルのBourne Shell/bin/shとして出荷されていました。 Solaris 11でksh93にアップデートされたとのことです。

4
zwol

あなたは実際にどちらかを使用する必要があります

#! /bin/env sh

または

#! /bin/env bash

そうすれば、そのシステムにインストールする方法でシェルを呼び出すことができます。

非常に安全にするには(egシングルユーザーの再起動の場合)shを使用します。それ以外の場合はbashを使用します。

0
Paul Evans