通常、シェルスクリプトには、スクリプトファイルの最初の行に次のコメントが含まれています:#!/bin/sh
。私が行った研究によると、これは「ハッシュバン」と呼ばれ、従来のコメントです。このコメントは、このファイルがディレクトリ/bin
の下のBourne Shellによって実行されることをUnixに通知します。
私の質問はその時点で始まります。これまで、#!/bin/bash
のようにこのコメントを見たことはありません。常に#!/bin/sh
です。ただし、UbuntuディストリビューションにはBourne Shellプログラムがありません。彼らはボーンアゲインシェル(bash)を持っています。
その点で、Ubuntuディストリビューションで記述されたシェルスクリプトにコメント#!/bin/sh
を配置することは正しいですか?
#!/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
以外のシステムでは失敗する可能性があります。
あなたはそれを逆に持っています。最近、_/bin/sh
_がボーンシェルになることはほとんどなく、_#! /bin/sh
_シーバンを使用するときに問題が発生するのはこのときです。
ボーンシェルは70年代後半に書かれたシェルで、以前のトンプソンシェル(sh
とも呼ばれます)に代わるものです。 80年代初頭に、David KornはBourne Shellの拡張機能をいくつか作成し、いくつかのバグと設計の厄介な問題を修正して(そしていくつかを導入し)、それをKorn Shellと呼びました。
90年代初頭、POSIXはKornシェルのサブセットに基づいてsh
languageを指定し、ほとんどのシステムは_/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には基づいていません³。これらのシェルのいくつか(bash
、zsh
、yash
、および一部のpdksh
派生物は、sh
として呼び出されたときにPOSIX準拠モードを有効にし、それ以外の場合はless準拠です)。
bash
(GNU Korn Shellへの回答)は、実際には唯一のオープンソースシェルです(他のシェルは一般に新しいものを取得していないksh88に基づいているため、現在維持されていると言えるでしょう) (macOS認定の一部として)POSIX準拠のsh
として認定されている90年代以降の機能。
_#! /bin/sh -
_ she-bangを使用してスクリプトを作成する場合は、標準のsh
構文を使用する必要があります(移植可能にする場合は、そのスクリプトで使用されるユーティリティの標準構文も使用する必要があります。シェルだけではありません。シェルスクリプトを解釈する際に関係します)。その場合、標準のsh
構文インタープリターのどの実装が使用されているかは関係ありません(ksh
、bash
...)。
それらを使用しない限り、それらのシェルが標準以上の拡張機能を持つことは問題ではありません。標準の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標準のスーパーセット)に基づいて記述されているため、両方のシェルで同じように機能するはずです。 zsh
のsh
エミュレーションまたはbosh
(おそらく_ksh93
_もyash
もlocal
が組み込まれていない(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
_を実行し、sh
はmyscript
に格納されているコンテンツコードを解釈し、コメント(_#
_で始まる)として最初の行を無視します)。
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シェルの別の再実装)に基づいています)
そのようなシステムでは#!/bin/sh
が(うまくいけば)提供されているため、スクリプトで/bin/sh
を使用できます。通常、bash
が(多かれ少なかれ)動作するようなリンクから提供されますsh
だろう。たとえば、sh
をbash
にリンクする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
スクリプトは移植性が高いはずです。
あなたが尋ねた
ubuntuディストリビューションで記述されたシェルスクリプトにコメント#!/ bin/shを配置することは正しいですか?
答えは、シェルスクリプトで何を書くかによって異なります。
移植可能なPOSIX準拠のスクリプトを厳密に使用し、bash固有のコマンドを使用しない場合は、can_/bin/sh
_を使用します。
Bashを搭載したマシンでスクリプトを使用しているだけで、bash固有の構文を使用したい場合は、を使用してください_/bin/bash
_を使用
スクリプトがさまざまなUNIXマシンで確実に機能するようにしたい場合は、shouldPOSIX準拠の構文のみを使用し、_/bin/sh
_
another Shell (例 ksh 、 zsh または tcsh )を定期的に使用しており、その構文をあなたのスクリプト、そしてあなたshouldは適切なインタプリタ(_/bin/ksh93
_、_/bin/zsh
_、または_/bin/tcsh
_)
「#!」コメントは常に/bin/bash
または/bin/sh
を使用するわけではありません。シェルスクリプティングだけでなく、インタプリタが何であれリストするだけです。たとえば、my pythonスクリプトは通常#!/usr/bin/env python
で始まります。
#!/bin/sh
と#!/bin/bash
の違いは、/bin/sh
が/bin/bash
へのシンボリックリンクであるとは限らないことです。多くの場合、常にではありません。 Ubuntuはここで注目すべき例外です。 CentOSではスクリプトは正常に機能しますが、Ubuntuではスクリプトが失敗しました。筆者は#!/bin/sh
でbash固有の構文を使用したためです。