web-dev-qa-db-ja.com

Bourne Shellがディストリビューションで利用できない場合、hashbangで/ bin / shを使用することは正しいですか?

通常、シェルスクリプトには、スクリプトファイルの最初の行に次のコメントが含まれています:#!/bin/sh。私が行った研究によると、これは「ハッシュバン」と呼ばれ、従来のコメントです。このコメントは、このファイルがディレクトリ/binの下のBourne Shellによって実行されることをUnixに通知します。

私の質問はその時点で始まります。これまで、#!/bin/bashのようにこのコメントを見たことはありません。常に#!/bin/shです。ただし、UbuntuディストリビューションにはBourne Shellプログラムがありません。彼らはボーンアゲインシェル(bash)を持っています。

その点で、Ubuntuディストリビューションで記述されたシェルスクリプトにコメント#!/bin/shを配置することは正しいですか?

15
Goktug

#!/bin/shは、すべてのUnixおよびUnixライクなディストリビューションで動作するはずです。通常、スクリプトがPOSIXに準拠している限り、これは最も移植性の高いハッシュバンと考えられます。 /bin/shシェルは、実際のシェルが/bin/shシェルを装ったものであるかどうかに関係なく、POSIXシェル標準を実装するシェルであると想定されています。


#!/bin/shは、Bourne Shellが維持されなくなったため、通常は単なるリンクになっています。多くのUnixシステムでは/bin/sh/bin/kshまたは/bin/ashへのリンクになりますが、多くのRHELベースのLinuxシステムでは/bin/bashへのリンクになりますが、Ubuntuおよび多くのDebianではベースのシステムは/bin/dashへのリンクです。すべてのシェルは、shとして呼び出されると、POSIX互換モードに入ります。

Hashbangは重要です。ただし、スクリプトがPOSIXに厳密に準拠している(重要度を強調するために繰り返されている)限り、他の方法よりもはるかに移植性が高くなります。

注:bashがPOSIXモードで呼び出された場合でも、[[や配列などの非POSIX機能がいくつか許可されます。これらはbash以外のシステムでは失敗する可能性があります。

16
jesse_b

あなたはそれを逆に持っています。最近、_/bin/sh_がボーンシェルになることはほとんどなく、_#! /bin/sh_シーバンを使用するときに問題が発生するのはこのときです。

ボーンシェルは70年代後半に書かれたシェルで、以前のトンプソンシェル(shとも呼ばれます)に代わるものです。 80年代初頭に、David KornはBourne Shellの拡張機能をいくつか作成し、いくつかのバグと設計の厄介な問題を修正して(そしていくつかを導入し)、それをKorn Shellと呼びました。

90年代初頭、POSIXはKornシェルのサブセットに基づいてshlanguageを指定し、ほとんどのシステムは_/bin/sh_を次のいずれかに変更しましたKornシェルまたはその仕様に準拠したシェル。 BSDの場合、最初に(ライセンス上の理由でBourne Shellを使用できなくなった後)_/bin/sh_を徐々に変更し、いくつかのksh拡張機能を備えたBourne ShellのクローンであるAlmquist ShellをPOSIX準拠にしました。

今日、すべてのPOSIXシステムには、ほとんどがPOSIXに準拠するsh(ほとんどの場合、必ずしも_/bin_ではないが、POSIXが指定するユーティリティのパスを指定しない)と呼ばれるシェルがあります。これは通常、ksh88、ksh93、pdksh、bash、ash、またはzsh²に基づいていますが、Bourne ShellはPOSIX準拠ではなかったため、Bourne Shellには基づいていません³。これらのシェルのいくつか(bashzshyash、および一部のpdksh派生物は、shとして呼び出されたときにPOSIX準拠モードを有効にし、それ以外の場合はless準拠です)。

bash(GNU Korn Shellへの回答)は、実際には唯一のオープンソースシェルです(他のシェルは一般に新しいものを取得していないksh88に基づいているため、現在維持されていると言えるでしょう) (macOS認定の一部として)POSIX準拠のshとして認定されている90年代以降の機能。

_#! /bin/sh -_ she-bangを使用してスクリプトを作成する場合は、標準のsh構文を使用する必要があります(移植可能にする場合は、そのスクリプトで使用されるユーティリティの標準構文も使用する必要があります。シェルだけではありません。シェルスクリプトを解釈する際に関係します)。その場合、標準のsh構文インタープリターのどの実装が使用されているかは関係ありません(kshbash...)。

それらを使用しない限り、それらのシェルが標準以上の拡張機能を持つことは問題ではありません。標準のCコードを記述し、一方のコンパイラ(gccなど)の拡張機能を使用しない限り、これはCコードの記述に似ています。コンパイラが準拠していれば、コンパイラの実装に関係なく、コードは正常にコンパイルされます。

ここで、_#! /bin/sh_シーバンを使用した場合の主な問題は、_/bin/sh_がBourne Shellであり、たとえば$((1+1))$(cmd)、_${var#pattern}_...この場合、次のような回避策が必要になることがあります。

_#! /bin/sh -
if false ^ true; then
  # in the Bourne Shell, ^ is an alias for |, so false ^ true returns
  # true in the Bourne Shell and the Bourne Shell only.
  # Assume the system is Solaris 10 (older versions are no longer maintained)
  # You would need to adapt if you need to support some other system
  # where /bin/sh is the Bourne Shell.
  # We also need to fix $PATH as the other utilities in /bin are
  # also ancient and not POSIX compatible.
  PATH=`/usr/xpg6/bin/getconf PATH`${PATH:+:}$PATH || exit
  export PATH
  exec /usr/xpg4/bin/sh "$0" "$@"
  # that should give us an environment that is mostly  compliant
  # to the Single UNIX Specification version 3 (POSIX.2004), the
  # latest supported by Solaris 10.
fi
# rest of the script
_

ちなみに、Ubuntuの_/bin/sh_は、デフォルトではbashではありません。最近のdashは、NetBSD shに基づいたシェルであり、マルチバイト文字をサポートしていないことを除いて、ほとんどがPOSIX準拠のAlmquistシェルに基づいています。 Ubuntuおよびその他のDebianベースのシステムでは、_/bin/sh_と_dpkg-reconfigure dash_)のbashまたはdashを選択できます。4。 Debianに付属しているshスクリプトは、Debianポリシー標準(POSIX標準のスーパーセット)に基づいて記述されているため、両方のシェルで同じように機能するはずです。 zshshエミュレーションまたはbosh(おそらく_ksh93_もyashlocalが組み込まれていない(Debianポリシーでは必須だがPOSIXではない))でも、おそらくそれらは問題なく動作します。

Unix.stackexchange.comでスコープ内にあるすべてのシステムには、どこかにPOSIX shがあります。それらのほとんどは_/bin/sh_を持っています(_/bin_ディレクトリを持たない非常にまれなものを見つけるかもしれませんが、おそらくそれを気にしません)、そしてそれは一般にPOSIX shインタープリターです(そしてまれなケース(代わりに(非標準)Bourne Shell)。

しかし、shは、システムで確実に見つけることができる唯一のシェルインタープリター実行可能ファイルです。他のシェルについては、macOS、Cygwin、およびほとんどのGNU/Linuxディストリビューションがbashを持っていることを確認できます。 SYSVから派生したOS(Solaris、AIX ...)には、通常ksh88、おそらくksh93があります。 OpenBSD、MirOSにはpdksh派生物があります。 macOSにはzshがあります。しかし、その中で、保証はありません。 bashやその他のシェルが_/bin_または他の場所にインストールされるかどうかは保証されません(たとえば、BSDの_/usr/local/bin_にインストールされている場合、通常はBSDにあります)。そしてもちろん、インストールされるシェルのバージョンは保証されません。

_#! /path/to/executable_は規約ではないことに注意してください。これはすべてのUnixライクなカーネルの機能です( 80年代前半に導入) by Dennis Ritchie )これは、_#!_で始まる最初の行にインタープリターのパスを指定することにより、任意のファイルを実行できるようにします。任意の実行可能ファイルにすることができます。

最初の行が_#! /some/file some-optional-arg_で始まるファイルを実行すると、カーネルは_/some/file_、スクリプトのパス、および元の引数を引数として、_some-optional-arg_を実行します。最初の行を_#! /bin/echo test_にして、何が起こっているかを確認できます。

_$ ./myscript foo
test ./myscript foo
_

_/bin/sh -_の代わりに_/bin/echo test_を使用すると、カーネルは_/bin/sh - ./myscript foo_を実行し、shmyscriptに格納されているコンテンツコードを解釈し、コメント(_#_で始まる)として最初の行を無視します)。


Bおそらく、Bourne Shellに基づく_/bin/sh_に遭遇する今日の唯一のシステムはSolaris 10です。Solarisは、下位互換性のためにBourne Shellをそこに保持することを決定した数少ないUnicesの1つです( POSIX sh言語は、Bourne Shellと完全に下位互換性がありません)(少なくともデスクトップおよびフルサーバーデプロイメントの場合)POSIX shが他の場所(ksh88に基づく_/usr/xpg4/bin/sh_内)にありますが、Solaris 11で変更されました_/bin/sh_はksh93になりました。他のものはほとんど消滅しています。

² MacOS/Xの_/bin/sh_は、以前はzsh でしたが、後でbashに変更されました。 POSIX zsh実装として使用されるのは、shの主な目的ではありません。そのshモードは、主に(source)POSIX shコードをzshスクリプトに埋め込んだり、呼び出したりできるようにするためのものです。

³最近 @ schily OpenSolarisシェル(Bourneシェルに基づくSVR4シェルをベースとする)を拡張してPOSIX準拠になりました bosh と呼ばれていますが、まだどのシステムでも使用されています。 Bourne Shellのコードに基づく2番目のPOSIX準拠シェルにする_ksh88_とともに

4 古いバージョンでは、mkshまたはそのより多くのPOSIX lkshインカネーションを使用することもできました。それはpdkshに基づくMirOS(以前のMirBSD)シェルで、それ自体はForsythシェル(Bourneシェルの別の再実装)に基づいています)

12

そのようなシステムでは#!/bin/shが(うまくいけば)提供されているため、スクリプトで/bin/shを使用できます。通常、bashが(多かれ少なかれ)動作するようなリンクから提供されますshだろう。たとえば、shbashにリンクするCentos7システムは次のとおりです。

-bash-4.2$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Dec  4 16:48 /bin/sh -> bash
-bash-4.2$ 

そのシステム専用のbashスクリプトを作成していて、bash機能を使用したい場合は、#!/bin/bashを使用することもできます。ただし、そのようなスクリプトは移植性の問題に悩まされます。たとえば、OpenBSDの場合、bashがインストールされるのは、管理者がそれをインストールするのに問題があり(私はしません)、その後/usr/local/bin/bashにインストールされた場合のみです。 /bin/bashではありません。厳密にPOSIX #!/bin/shスクリプトは移植性が高いはずです。

8
thrig

あなたが尋ねた

ubuntuディストリビューションで記述されたシェルスクリプトにコメント#!/ bin/shを配置することは正しいですか?

答えは、シェルスクリプトで何を書くかによって異なります。

  • 移植可能なPOSIX準拠のスクリプトを厳密に使用し、bash固有のコマンドを使用しない場合は、can_/bin/sh_を使用します。

  • Bashを搭載したマシンでスクリプトを使用しているだけで、bash固有の構文を使用したい場合は、を使用してください_/bin/bash_を使用

  • スクリプトがさまざまなUNIXマシンで確実に機能するようにしたい場合は、shouldPOSIX準拠の構文のみを使用し、_/bin/sh_

  • another Shell (例 kshzsh または tcsh )を定期的に使用しており、その構文をあなたのスクリプト、そしてあなたshouldは適切なインタプリタ(_/bin/ksh93_、_/bin/zsh_、または_/bin/tcsh_)

6
Stobor

「#!」コメントは常に/bin/bashまたは/bin/shを使用するわけではありません。シェルスクリプティングだけでなく、インタプリタが何であれリストするだけです。たとえば、my pythonスクリプトは通常#!/usr/bin/env pythonで始まります。

#!/bin/sh#!/bin/bashの違いは、/bin/sh/bin/bashへのシンボリックリンクであるとは限らないことです。多くの場合、常にではありません。 Ubuntuはここで注目すべき例外です。 CentOSではスクリプトは正常に機能しますが、Ubuntuではスクリプトが失敗しました。筆者は#!/bin/shでbash固有の構文を使用したためです。

3
aragaer