#!/ bin / bashと#!/ bin / shを使用する必要がある場合


104

ときである#!/bin/bashよりも、より適切な#!/bin/shシェルスクリプトでは?


55
bash関数と構文ではなく関数と構文を使用している場合sh
木梅


3
それが誰かを助けるならば、あなたのスクリプトがシバンを持っているならば、私はそれvimが強調するbash-ismsに気づきました#!/bin/sh。私は、bashbashの機能が必要になり始めるのに十分なものになった場合にのみ変更します。
SeldomNeedy

@SeldomNeedyただし、デフォルトで強調表示されているものの一部は、POSIXシェルで正常に機能します。$(...)特に不快です。また、それらのいくつかは微妙で、[ <(...)およびcmd >& fileエラーのハイライトは、例えば、彼らはただの有無にかかわらず、彼らは何を意味するかのために特別なハイライトを持っていない取得しないg:is_bash]
Random832

@ Random832 vimのissue-trackerでこのトピックに関する最近の活動があったようです。
-SeldomNeedy

回答:


150

要するに:

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

  • sh機能のみに固執している限り、使用でき(おそらくそうすべきです)#!/bin/sh、どのシェルであってもスクリプトは正常に動作します。

  • bash固有の機能(配列など)の使用を開始する場合は、bashを具体的に要求する必要/bin/shがあります。すでにシステムでbashを起動している場合でも、他の人のシステムでは実行されず、スクリプトはそこで実行されないためです。(もちろん、zshとkshにも同じことが当てはまります。)shellcheckを使用して、バシズムを識別することができます。

  • スクリプトが個人使用のみの場合でも、一部のOS /bin/shはアップグレード中に変更されることに気付くかもしれません。たとえば、Debianでは以前bashでしたが、後に非常に最小限のダッシュに置き換えられました。バシズムを使用したが、#!/bin/sh突然壊れたスクリプト。

しかしながら:

  • でも#!/bin/bash非常に正しくありません。異なるシステムでは、bashは/usr/binまたは/usr/pkg/binまたはに存在し/usr/local/binます。

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


10
素敵な答え。CWにするつもりでしたか?
木梅

3
bashが実行された場合の単なる発言は、機能/bin/shを模倣しようとしshます(manページを参照)。envtoolはほとんどのディストリビューションで見られるはずのposixツールですが、posixを尊重しない人もいるかもしれません。
ブライス

8
いや、実際にはPOSIXは、具体的に述べ、であると仮定することはできません/bin:「アプリケーションがシェルに標準PATHは/ binに/ SHまたは/ usr / binに/ shのいずれかであると想定することはできない、と判断されなければならないことに注意すべきですgetconf PATHによって返されたPATHの問い合わせにより、返されたパス名がシェルのビルトインではなく絶対パス名であることを確認します。この質問、特にこの回答もご覧ください。
テルドン

12
うーん、それで、POSIXは実際に#!スクリプトを動作させるための移植可能な方法を定義していないということですか?
荒廃

4
POSIX shはBourneではありません。Bourneの直接の子孫であるというよりは、初期のkshの派生物です。それらを区別するのは簡単ですecho foo ^ cat。POSIXsh foo ^ catで放出しfoo、Bourneでのみ放出します(^そこにパイプ文字があります)。
チャールズダフィー

18

スクリプトの開発とデバッグに実際に使用したシェルに対応するシェバンを使用します。つまり、ログインシェルがbashであり、端末でスクリプトを実行可能ファイルとして実行する場合は、を使用します#!/bin/bash。配列(またはbash認識している機能)を使用していないため、好きなシェルを選択しても安全だと思い込まないでください。シェル(echo、関数、ループ、名前を付ける)には多くの微妙な違いがありますが、適切なテストなしでは発見できません。

これを考慮してください:あなたが離れて#!/bin/bash、あなたのユーザーがそれを持っていない場合、彼らは次のような明確なエラーメッセージが表示されます

Error: /bin/bash not found

ほとんどのユーザーは、適切なパッケージをインストールすることにより、1分以内にこれを修正できます。一方、シバンをに置き換えて、へのシンボリックリンクがある#!/bin/shシステムでテストすると、持っていないユーザーが問題を抱えることになります。ほとんどの場合、次のような不可解なエラーメッセージが表示されます。/bin/sh/bin/bashbash

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

これを修正するには数時間かかる場合があり、どのシェルを使用すべきかについての手がかりはありません。

シバンで別のシェルを使用する理由は多くありません。1つの理由は、使用したシェルが普及していない場合です。もう1つはsh、一部のシステムでパフォーマンスを大幅に高速化することです。また、スクリプトがパフォーマンスのボトルネックになります。その場合は、ターゲットシェルでスクリプトを徹底的にテストし、シバンを変更します。


@Hasturコメントはありません。シバンは、どのシェルを使用してスクリプトを実行するかを確実に定義しますが、私の答えはそうではないと思いますか?
ドミトリーグリゴリエフ

1
忘れてください。私は一部誤解「あなたが使用したいと思いますなぜ」を ...
ハスター

6

あなただけを使用する必要があります#! /bin/sh

シェルスクリプトでbash(またはzsh、またはfish、...)拡張機能を使用しないでください。

シェル言語のすべての実装(シェル自体に付随するすべての「ユーティリティ」プログラムを含む)で動作するシェルスクリプトのみを記述してください。これらの日、あなたはすることができますおそらく取るPOSIX.1-2001ないシェルとユーティリティがすることができ、何のために権威として-2008)をしていますが、(例えばSolarisのポートにするとレガシーシステムへのスクリプトを1日と呼ばれることもあることに注意してくださいまたはAIX)シェルおよびユーティリティが1992年頃に凍結された。

まじで?

はい、真剣に。

事はここにあります:シェルはひどいプログラミング言語です。唯一の目的/bin/shは、すべての Unixインストールで保証されている唯一のスクリプトインタープリターであることです。

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

したがって、bashスクリプトを作成するオプションがある場合は、代わりにひどくないプログラミング言語を使用するオプションがあります。

さて、単純なシェルスクリプト、つまりcronジョブなどからシーケンスでいくつかのプログラムを実行するだけの種類のスクリプトは、シェルスクリプトのままにしておくことで問題はありません。ただし、単純なシェルスクリプトには、配列や関数は必要ありません[[。また、他に選択肢がない場合にのみ、複雑なシェルスクリプトを記述する必要があります。たとえば、Autoconfスクリプトは適切なシェルスクリプトです。ただし、これらのスクリプトは、構成中のプログラムに関連するすべてのインカネーションで実行/bin/shする必要があります。つまり、拡張機能は使用できません。最近の古いプロプライエタリUnixを気にする必要はないでしょうが、おそらく現在インストールされていないオープンソースBSD 気にする必要があります。bashデフォルトでは、最小限のシェルとのみを提供する組み込み環境busybox

結論として、ポータブルシェル言語では使用できない機能を望んでいることに気付いた瞬間、つまり、スクリプトが複雑すぎてシェルスクリプトを維持できないという兆候です。代わりに、より良い言語で書き直してください。


4
申し訳ありませんが、それは少しばかげています。はい、i)配布され、ii)別の環境に送られるものを書いている場合は、basicに固執する必要がありますsh。ただし、これは、他のシェルを使用しないでくださいと述べることにはほど遠いです。毎日何千もの(おそらくもっと多くの)スクリプトが記述されており、それらの大部分は1台のマシンでしか実行されません。あなたのアドバイスは製品コードでは意味がありますが、ほとんどのスクリプトが書かれている毎日の「sysdaminy」ジョブには意味がありません。自分のスクリプトが自分とLinuxマシンでしか使用されないことがわかっている場合、bashは問題ありません。
テルドン

1
@terdonポイントは、bashスクリプトを記述するオプションがある場合、perl(または何でも)スクリプトを記述するオプションもあるということです。これは常により良い選択です。
zwol

@terdon答えは確かに愚かではなく、あなたのコメントは単純です。シェルスクリプトは、Perlなどに比べてデバッグがひどいため、グラフィカルなデバッグ機能を備えた完全なIDEを簡単に使用できます。さらに、毎日何か小さなことをするために書かれたスクリプトのほとんどは、変更され、何度も何度も変更され、成長し、同僚やネットなどに例としてコピーされる傾向があります。
トーステンシェーニング

@ThorstenSchöning 少しばかげたことを言っ。これがUnixとLinux、またはスタックオーバーフローである場合、私も同意するかもしれません。一般的なベストプラクティス、またはプロのプログラマーについて話している場合は、もちろん基本的なPOSIX shに固執することをお勧めします。しかし、これはスーパーユーザーであり、エンドユーザーを対象としたサイトであり、シェルスクリプトを記述する際にbashやzshを使用しないように人々に伝えているサイトは、私の意見では極端です。
テルドン

@terdon エンドユーザーが複雑なシェルスクリプトを書くことを思いとどまらせることは、私の意見では、実際により重要です。専門家は平均して高いスキルレベルを持ち(したがって、複雑なシェルスクリプトの落とし穴に対処できる可能性が高くなります)、どの環境に移植する必要があるかをある程度正確に知っている必要があり、giveめないように支払われています欲求不満で。
zwol

4

通常、機能よりも時間が重要な場合は、より高速なシェルを使用します。shは多くの場合、ダッシュにエイリアスされ、ルートのcronタスクまたは(ナノ)秒ごとにカウントされるバッチ操作に使用される傾向があります。


2
ファイルシステムから追加のシェルインタープリターをロードすると、このような利点が無効になる可能性があり、ナノ秒(実際のマシンサイクルと同程度)がカウントされるものはすべて、Cおよびアセンブリ言語プログラマーのドメインです。
rackandboneman

ナノ秒は、数十億のcronジョブで違いを生むだけであり、とにかくcronはそれほど多くを処理できません。
ドミトリーグリゴリエフ

1
mckenzmが少し誇張されていたとしても、パフォーマンスが高いほど良いことは否定できません。「ナノ」の部分にこだわらないでください。(ナノ秒は、リアルタイムシステムなどの内部ループでない限り、Cではカウントされません!)
jpaugh

1
@jpaugh特定の操作に少なくとも特定の時間がかかると想定する(レガシー)システムを使用している場合を除きます。それが起こる!
JAB

3

さらに簡単に言うとsh、ほとんどのシステムでの移植性が最も重要でありbash、bashのバージョンでサポートされている場合、アレイなどの特定の機能を使用したい場合に使用します。


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

最も安全なパス。ハードコーディングされた場合、/ usr / bin /になりますshellOfChoiceが、私は常に現在使用しようとしている新しい規則です-変更PATHを介した「デフォルトの場所」が変更される可能性があるため:

#!/ usr / bin / env shまたは
#!/ usr / bin / env bash
またはperlスクリプトの場合
#!/ usr / bin / env perl -w

もちろん、スクリプトが新しいPATHを決して自動的に取得しない理由がある場合は、それをハードコーディングし続けます-そして、/ usr / bin / somethingが使用する可能性が最も高いパスになります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.