シェルスクリプトの中で#!/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