linux – いつ#!/bin/bashを使わなければならないのか、いつ#!/bin/shを使わなければならないのか?

linux shell-script

シェルスクリプトの中で#!/bin/shよりも#!/bin/bashの方が適切なのはいつですか?

  107  Hendré  2016-10-10


ベストアンサー

In short:

  • POSIX sh 仕様のスーパーセットを実装したシェルがいくつかあります。異なるシステムでは、/bin/sh は ash, bash, dash, ksh, zsh, &c へのリンクになるかもしれません。(ただし、常に sh と互換性があります – csh や fish とは決して互換性がありません)

  • sh の機能のみにこだわる限り、#!/bin/sh を使うことができ (おそらく使うべきでしょう)、スクリプトはどのシェルであっても問題なく動作するはずです

  • bash 固有の機能 (配列など) を使い始める場合は、特に bash を要求すべきです – なぜなら、/bin/sh があなたのシステムですでに bash を起動していたとしても、他の人のシステムでは起動していないかもしれないし、あなたのスクリプトはそこでは実行されないからです。(もちろん、zsh や ksh も同様です。) bashisms を特定するには、shellcheck を使うことができます

  • 個人的な利用のみを目的としたスクリプトであっても、OSによってはアップグレードの際に /bin/sh が変更されることに気づくかもしれません – 例えば、Debianでは以前はbashでしたが、後に非常に小さなダッシュに置き換えられました。bashisms を使っていたスクリプトで #!/bin/sh を使っていたものが突然壊れてしまいました

However:

  • #!/bin/bashでさえ、あまり正しくありません。異なるシステムでは、bash は /usr/bin/usr/pkg/bin/usr/local/bin にあるかもしれません

  • より信頼性の高いオプションは、#!/usr/bin/env bashで、$PATHを使用します。(env ツール自体も厳密には保証されていませんが、/usr/bin/env/bin/bash よりも多くのシステムで動作します)

152  community wiki  2016-10-21


スクリプトの開発やデバッグに実際に使用したシェルに対応するシェルを使用してください。例えば、ログインシェルが bash で、ターミナルでスクリプトを実行可能な状態で実行している場合、 #!/bin/bash を使用します。配列を使っていないから(あるいは bash の機能を知っているからといって)、好きなシェルを選んでも大丈夫だと決めつけないでください。シェル間には多くの微妙な違いがあります (echo, 関数, ループなど)

これを考えてみましょう: #!/bin/bashを残したままで、ユーザーが#!/bin/bashを持っていない場合、次のような明確なエラーメッセージが表示されます

Error: /bin/bash not found

ほとんどのユーザは、適切なパッケージをインストールすることで、1分以内にこれを修正することができます。一方、shebang を #!/bin/sh に置き換えて /bin/sh/bin/bash へのシンボリックリンクになっているシステムでテストした場合、 bash を持っていないユーザは困ったことになるでしょう。彼らはほとんどの場合、次のような暗号化されたエラーメッセージを見るでしょう

Error in script.sh line 123: error parsing token xyz

これは修正に何時間もかかるかもしれませんし、どのシェルを使うべきだったかの手掛かりもないでしょう

シェルバンで違うシェルを使いたいと思う理由はあまりありません。一つは、今まで使っていたシェルが普及していない場合です。もう一つは、システムによってはかなり高速なshで性能を上げたい、スクリプトが性能のボトルネックになってしまう、という場合です。その場合は、ターゲットシェルでスクリプトを徹底的にテストしてから、 シェルの変更を行ってください

18  Dmitry Grigoryev  2016-10-10


#! /bin/shだけは絶対に使ってはいけない

シェルスクリプトの中で bash (または zsh, fish, ….) の拡張子を使うべきではありません

シェル言語のどのような実装でも動作するシェルスクリプトを書くべきです (シェル自体と一緒に動作するすべての「ユーティリティ」プログラムを含む)。最近では、POSIX.1-2001 (-2008ではありません) をシェルとユーティリティの機能についての権威あるものとして受け止めることができるでしょうが、1992年頃にシェルとユーティリティが凍結されたレガシーシステム (Solaris や AIX など) にスクリプトを移植するように要求される日が来るかもしれないことに注意してください

What, seriously?!

Yes, seriously.

シェルはひどいプログラミング言語です。シェルの唯一の長所は、/bin/shがすべてのUnixのインストールで保証されている唯一無二のスクリプトインタプリタであるということです

もう一つ、Perl 5 のコアとなるインタプリタのいくつかのイテレーション (/usr/bin/perl) は (/(usr|opt)(/(local|sfw|pkg)?)?/bin/bash よりもランダムに選択された Unix のインストールで利用できる可能性が高いです。他の優れたスクリプト言語 (Python, Ruby, node.js など – シェルと比較する場合は PHP や Tcl もそのカテゴリに含めます) も、bash や他の拡張シェルとほぼ同じくらい利用可能です

そのため、bashスクリプトを書くという選択肢があるのであれば、代わりに恐ろしくないプログラミング言語を使うという選択肢もあります

さて、単純なシェルスクリプトは、cronジョブなどからいくつかのプログラムを連続して実行するだけのもので、シェルスクリプトのままにしておいても何も問題はありません。しかし、単純なシェルスクリプトには配列や関数、[[すら必要ありません。また、複雑なシェルスクリプトは、他に選択肢がない場合にのみ書くべきです。例えば、Autoconf スクリプトは、正しくはシェルスクリプトです。しかし、これらのスクリプトは、設定されているプログラムに関連する /bin/sh のすべての化身で実行されなければなりません。最近の古いプロプライエタリなUnixを気にする必要はないかもしれませんが、現在のオープンソースのBSDや、デフォルトでbashをインストールしていないものや、最小限のシェルとbusyboxしか与えてくれない組み込み環境を気にする必要があるかもしれません

結論として、ポータブルシェル言語では利用できない機能が欲しいと思った瞬間、それはスクリプトがシェルスクリプトのままでは複雑になりすぎているというサインです。代わりに、より良い言語に書き換えてください

5  zwol  2016-10-14


一般的に、機能よりも時間が重要な場合は、より高速なシェルを使うことになります

4  mckenzm  2016-10-11


もっと簡単に言うと、ほとんどのシステムで移植性を重視する場合はshを、配列などの特定の機能を使いたい場合はbashを、bashのバージョンがサポートしている場合はbashを使ってください

3  Spencer Williams  2016-10-11


  • sh (ほとんどの場合)、特に必要であれば bash (または ksh など)

ハードコードされたときに、/usr/bin/shellOfChoiceであろうが、私は今、常に使用しようとしている新しい規約 – 変更PATHを介して’デフォルトの場所’として変更することができます

/usr/bin/env sh や #! /usr/bin/env bash や、perl スクリプトなどの場合は #!

もちろん、スクリプトが自動的に新しいパスを取らないようにする理由がある場合は、ハードコードされたパスを継続してください – /usr/bin/something が最も可能性の高いパスであるべきです

1  Michael Felt  2016-11-24


タイトルとURLをコピーしました