通常、シェルスクリプトには、スクリプトファイルの最初の行に次のコメントが含まれています#!/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/sh
Bourneシェルはもはやメンテナンスされなくなり、通常はリンクです。多くのUnixシステムではへ/bin/sh
のリンクになり/bin/ksh
、/bin/ash
多くのRHELベースのLinuxシステムではへのリンクになり/bin/bash
ますが、Ubuntuや多くのDebianベースのシステムではへのリンクになります/bin/dash
。として呼び出されると、すべてのシェルはsh
POSIX互換モードに入ります。
hashbangは、スクリプトが厳密にPOSIXに準拠している限り(重要性を強調するために繰り返される)他の方法よりも移植性が高いため、重要なプレースホルダーです。
注:POSIXモードで呼び出されると、配列などのbash
POSIX以外の一部のアイテムはまだ許可されています。[[
これらの操作は、bash
システムでないと失敗する可能性があります。
答え2
あなたはそれを逆さまに持っています。/bin/sh
もはやBourneシェルではありません。#! /bin/sh
she-bangを使用する場合にのみ問題が発生します。
Bourneシェルは、以前のThompsonシェル(Bourneシェルとも呼ばれる)に代わって1970年代後半に作成されたシェルですsh
。 1980年代初頭、David KornはBourneシェルのいくつかの拡張を作成し、いくつかのバグとデザインの厄介さを修正し(そしていくつかの紹介)、それをKornシェルと呼びました。
1990年代初頭、POSIXは次のように述べました。sh
言語/bin/sh
Kornシェルのサブセットに基づいて、ほとんどのシステムはKornシェルまたはこの仕様に準拠したシェルに変更されました。 BSDの場合、/bin/sh
最初は(ライセンスの問題のためにBourneシェルを使用できなくなりました)、Almquistシェルを徐々に変更しました。 Almquistシェルはいくつかのksh拡張子を持つBourneシェルのレプリカなので、POSIXと互換性があります。
今日、すべてのPOSIXシステムにはほとんどPOSIXと互換性のあるシェルがありますsh
(最も一般的ですが、/bin
POSIXでは必ずしもそうではありませんが、指定するユーティリティへのパスを指定しません)。通常、ksh88、ksh93、pdksh、bash、ash、またはzsh²に基づいていますが、BourneシェルはPOSIXと互換性がないため、Bourneシェルに基づいていません。これらのシェルの一部(bash
および一部の派生プログラムは、およびとして呼び出されるとPOSIX互換モードを有効にします。zsh
yash
pdksh
sh
少ないそうでなければ、規制に従います)。
bash
(Kornシェルに対するGNUの回答)は、実際にオープンソースで認証された唯一のものです(他のシェルは、通常90年代以降に新機能を受けていないksh88に基づいているため、現在メンテナンス中の場合にのみ可能です)。 POSIX標準sh
(macOS認証の一部)
she-bangを使用してスクリプトを作成するときは、標準構文を使用する必要があります#! /bin/sh -
(移植性が必要な場合は、スクリプトで使用されるユーティリティの標準構文も使用する必要があります。シェルをsh
解釈するときはシェルスクリプトに関するものではありません)。sh
標準どの構文ソルバー実装が使用されるかは問題ではありません(ksh
、bash
...)。
これらのシェルを使用しない限り、標準以上の拡張機能があるかどうかは重要ではありません。 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
現在、dash
NetBSDベースのシェルsh
自体はマルチバイト文字をサポートしていないことを除いて、主にPOSIXと互換性のあるAlmquistシェルに基づいています。 Ubuntuやその他のDebianベースのシステムでは、bash
および)4dash
から/bin/sh
選択できます。 Debianに付属のスクリプトは、Debianポリシー標準(POSIX標準の親セット)に従って作成されているため、両方のシェルで同じように機能する必要があります。エミュレーションではうまく機能することがわかります(組み込み機能がある場合とない場合があります(Debianポリシーでは必要ですがPOSIXでは必要ありません)。dpkg-reconfigure dash
sh
zsh
sh
bosh
ksh93
yash
local
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/sh
BourneシェルベースのシステムはSolaris 10です。 Solarisは、以前のバージョンとの互換性のためにBourneシェルを維持することに決めた数少ないUnicesの1つです(POSIXsh
言語は、Bourneシェルとの以前のバージョンの互換性をまだ完全に実装していません)。そして(少なくともデスクトップとフルサーバー展開の場合)sh
他の場所(/usr/xpg4/bin/sh
ksh88ベース))POSIXがありましたが、Solaris 11で変更されており、/bin/sh
現在はksh93です。残りのほとんどは期限切れです。
²MacOS / Xは/bin/sh
以前zsh
でしたが、後でに変更されましたbash
。主な焦点はzsh
POSIX実装としては使用されませんsh
。主なモードは、sh
スクリプトにsource
POSIXsh
コードを挿入または呼び出し()できることです。zsh
最近、@ヒリーOpenSolarisシェル(SVR4シェルベース、Bourneシェルベース)をPOSIX互換に拡張しました。bosh
しかし、私はまだどのシステムでもそれが使用されていることを知りません。これに加えて、ksh88
Bourneシェルコードに基づいた2番目のPOSIX互換シェルになります。
4mksh
以前のバージョンでは、より多くのPOSIXバージョンを使用することもできますlksh
。これはpdkshベースのMirOS(以前のMirBSD)シェルで、このシェル自体はForsythシェル(Bourneシェルの別の再実装)に基づいています。
答え3
#!/bin/sh
/bin/sh
はい、そのようなシステムで提供されているように、(希望的に)一般的に言葉のように動作させるいくつかの接続を介してスクリプトでそれを使用できます。たとえば、これは次に接続されたCentos7システムです。bash
sh
sh
bash
-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スクリプトは、移植性が高くなければなりません。bash
bash
bash
/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