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

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

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

それから私の問題が始まりました。今までそのようなコメントは見たことがありません#!/bin/bash。いつも#!/bin/sh。しかし、UbuntuディストリビューションにBourne Shellプログラムはありません。 Bourne Again Shell(bash)があります。

#!/bin/shそれでは、Ubuntuディストリビューション用に書かれたシェルスクリプトにコメントを入れるのは正しいですか?

答え1

#!/bin/shすべてのUnixおよびUnixファミリーディストリビューションで動作する必要があります。スクリプトがPOSIX仕様に準拠している限り、通常は最も移植性の高いハッシュバンと見なされます。シェルは、シェルとして偽装する実際のシェルに/bin/sh関係なく、POSIXシェル標準を実装するシェルでなければなりません。/bin/sh


#!/bin/shBourneシェルはもはやメンテナンスされなくなり、通常はリンクです。多くのUnixシステムではへ/bin/shのリンクになり/bin/ksh/bin/ash多くのRHELベースのLinuxシステムではへのリンクになり/bin/bashますが、Ubuntuや多くのDebianベースのシステムではへのリンクになります/bin/dash。として呼び出されると、すべてのシェルはshPOSIX互換モードに入ります。

hashbangは、スクリプトが厳密にPOSIXに準拠している限り(重要性を強調するために繰り返される)他の方法よりも移植性が高いため、重要なプレースホルダーです。

注:POSIXモードで呼び出されると、配列などのbashPOSIX以外の一部のアイテムはまだ許可されています。[[これらの操作は、bashシステムでないと失敗する可能性があります。

答え2

あなたはそれを逆さまに持っています。/bin/shもはやBourneシェルではありません。#! /bin/shshe-bangを使用する場合にのみ問題が発生します。

Bourneシェルは、以前のThompsonシェル(Bourneシェルとも呼ばれる)に代わって1970年代後半に作成されたシェルですsh。 1980年代初頭、David KornはBourneシェルのいくつかの拡張を作成し、いくつかのバグとデザインの厄介さを修正し(そしていくつかの紹介)、それをKornシェルと呼びました。

1990年代初頭、POSIXは次のように述べました。sh 言語/bin/shKornシェルのサブセットに基づいて、ほとんどのシステムはKornシェルまたはこの仕様に準拠したシェルに変更されました。 BSDの場合、/bin/sh最初は(ライセンスの問題のためにBourneシェルを使用できなくなりました)、Almquistシェルを徐々に変更しました。 Almquistシェルはいくつかのksh拡張子を持つBourneシェルのレプリカなので、POSIXと互換性があります。

今日、すべてのPOSIXシステムにはほとんどPOSIXと互換性のあるシェルがありますsh(最も一般的ですが、/binPOSIXでは必ずしもそうではありませんが、指定するユーティリティへのパスを指定しません)。通常、ksh88、ksh93、pdksh、bash、ash、またはzsh²に基づいていますが、BourneシェルはPOSIXと互換性がないため、Bourneシェルに基づいていません。これらのシェルの一部(bashおよび一部の派生プログラムは、およびとして呼び出されるとPOSIX互換モードを有効にします。zshyashpdkshsh少ないそうでなければ、規制に従います)。

bash(Kornシェルに対するGNUの回答)は、実際にオープンソースで認証された唯一のものです(他のシェルは、通常90年代以降に新機能を受けていないksh88に基づいているため、現在メンテナンス中の場合にのみ可能です)。 POSIX標準sh(macOS認証の一部)

she-bangを使用してスクリプトを作成するときは、標準構文を使用する必要があります#! /bin/sh -(移植性が必要な場合は、スクリプトで使用されるユーティリティの標準構文も使用する必要があります。シェルをsh解釈するときはシェルスクリプトに関するものではありません)。sh標準どの構文ソルバー実装が使用されるかは問題ではありません(kshbash...)。

これらのシェルを使用しない限り、標準以上の拡張機能があるかどうかは重要ではありません。 Cコードを書くのと同じように、標準のCコードを書いていて、あるコンパイラ(たとえば)またはgcc別のコンパイラへの拡張を使用しない限り、コードはコンパイラの実装に関係なく(コンパイラが互換性がある限り)大丈夫です。通常。

ここで、#! /bin/shあなたの主な問題は、Bourneシェルを持つシステムが、、.../bin/shなどの標準機能をサポートしていないことです。この場合、次の回避策が必要な場合があります。$((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現在、dashNetBSDベースのシェルsh自体はマルチバイト文字をサポートしていないことを除いて、主にPOSIXと互換性のあるAlmquistシェルに基づいています。 Ubuntuやその他のDebianベースのシステムでは、bashおよび)4dashから/bin/sh選択できます。 Debianに付属のスクリプトは、Debianポリシー標準(POSIX標準の親セット)に従って作成されているため、両方のシェルで同じように機能する必要があります。エミュレーションではうまく機能することがわかります(組み込み機能がある場合とない場合があります(Debianポリシーでは必要ですがPOSIXでは必要ありません)。dpkg-reconfigure dashshzshshboshksh93yashlocal

unix.stackexchange.comの範囲内のすべてのシステムには、どこかにPOSIXがありますsh 。それらのほとんどは、1つ/bin/sh(ディレクトリのない非常にまれなものを見つけることができますが、/binおそらくそれを気にしません)と通常POSIXshインタプリタ(まれに(非標準)Bourneシェル)を持っています。

ただし、shこれはシステムで見つけることができる唯一のシェルソルバー実行可能ファイルです。他のシェルの場合、macOS、Cygwin、およびほとんどのGNU / Linuxディストリビューションには、bash.SYSV派生オペレーティングシステム(Solaris、AIX ...)が通常ksh88およびksh93を持つことがあります。 OpenBSDおよびMirOS用のpdksh派生があるでしょう。 macOSにはそのような機能がありますzsh。しかし、それ以上は保証できません。bashこれらの他のシェルがそこにインストールされるのか、それとも別の場所にインストールされるのかを保証することはできません(たとえば、/binインストール時に通常はBSDにあります)。/usr/local/binもちろん、インストールされるシェルのバージョンは保証されません。

#! /path/to/executableそうではありませんので参考にしてください習慣、これはすべてのUnixシリーズカーネルの機能です(1980年代初頭、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最初の行はコメント(で始まる)なので無視します#


今日私たちが遭遇する唯一の/bin/shBourneシェルベースのシステムはSolaris 10です。 Solarisは、以前のバージョンとの互換性のためにBourneシェルを維持することに決めた数少ないUnicesの1つです(POSIXsh言語は、Bourneシェルとの以前のバージョンの互換性をまだ完全に実装していません)。そして(少なくともデスクトップとフルサーバー展開の場合)sh他の場所(/usr/xpg4/bin/shksh88ベース))POSIXがありましたが、Solaris 11で変更されており、/bin/sh現在はksh93です。残りのほとんどは期限切れです。

²MacOS / Xは/bin/sh以前zshでしたが、後でに変更されましたbash。主な焦点はzshPOSIX実装としては使用されませんsh。主なモードは、shスクリプトにsourcePOSIXshコードを挿入または呼び出し()できることです。zsh

最近、@ヒリーOpenSolarisシェル(SVR4シェルベース、Bourneシェルベース)をPOSIX互換に拡張しました。boshしかし、私はまだどのシステムでもそれが使用されていることを知りません。これに加えて、ksh88Bourneシェルコードに基づいた2番目のPOSIX互換シェルになります。

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

答え3

#!/bin/sh/bin/shはい、そのようなシステムで提供されているように、(希望的に)一般的に言葉のように動作させるいくつかの接続を介してスクリプトでそれを使用できます。たとえば、これは次に接続されたCentos7システムです。bashshshbash

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

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

答え4

「#!」コメントは常に/bin/bashまたはと共に使用されません/bin/sh。シェルスクリプトだけでなく、インタプリタが何であるかをリストします。たとえば、私のPythonスクリプトは一般的に#!/usr/bin/env python

#!/bin/sh今との違いは、常にシンボリックリンクではないこと#!/bin/bashです。頻繁ではありませんが、必ずしもそうではありません。 Ubuntuは注目すべき例外です。 CentOSではスクリプトがうまく実行されていますが、作成者はbash固有の構文を使用していたため、Ubuntuは失敗するのを見ました。/bin/sh/bin/bash#!/bin/sh

関連情報