ファイルはシステムによって認識される実行可能ファイルのタイプではないため、そのファイルを実行する権限があると仮定すると、execve()
システムコールは通常ENOEXEC
(実行可能ファイルではない)エラーで失敗します。
その場合に発生するのは、コマンドを実行するために使用されるアプリケーションまたはライブラリ関数、あるいはその両方です。
たとえば、シェル、execlp()
/ execvp()
libc関数などです。
他のほとんどのアプリケーションは、コマンドを実行するときにこれらのいずれかを使用します。それらはの方法によって、例えばシェルを呼び出すsystem("command line")
典型的に起動するlibcの関数sh
そのコマンドラインを解析する(パスはそのようなコンパイル時(で決定することができる/bin/sh
VS /usr/xpg4/bin/sh
Solaris上))、またはシェルたinvokeに格納されている$SHELL
ように、それ自体でvi
その !
コマンド、またはxterm -e 'command line'
他の多くのコマンド(のsu user -c
代わりにユーザーのログインシェルを呼び出します$SHELL
)。
一般に、先頭にないシバンレステキストファイル#
はsh
スクリプトと見なされます。sh
ただし、どちらであるかは異なります。
execlp()
/ execvp()
、execve()
返さENOEXEC
れると通常sh
それを呼び出します。sh
複数の標準に準拠できるために複数のシステムsh
がある場合、通常、コンパイル時に(異なるパスを参照する異なるコードのblobをリンクすることによりexecvp()
/ を使用してアプリケーションの)決定されます。たとえば、Solarisでは、(標準のPOSIX )または(Solaris 10以前の場合はBourneシェル(旧式のシェル)、Solaris 11の場合はksh93)になります。execlp()
sh
/usr/xpg4/bin/sh
sh
/bin/sh
シェルに関しては、さまざまなバリエーションがあります。bash
、AT&T ksh
、Bourneシェルは通常exec
、をシミュレートした後(execve()
エクスポートされていないすべての変数を設定解除し、すべてのclose-on-exec fdsを閉じ、すべてのカスタムトラップを削除し、エイリアス、関数...(モードでbash
スクリプトを解釈しsh
ます)。yash
(と自分自身が実行されますsh
ようargv[0]
にあるのでsh
、それを解釈するモード)。
zsh
、pdksh
、ash
ベースシェルは、典型的に呼び出すsh
(コンパイル時に決定されたパス)。
用csh
してtcsh
(とsh
いくつかの初期のBSD)、ファイルの最初の文字がある場合#
、その後、彼らはそれを解釈するために自分自身を実行し、そしてだろうsh
そう。それは、シェバン前の時代にさかのぼり、Bourneシェルではなくコメントとしてcsh
認識#
したため、#
cshスクリプトであるというヒントになりました。
fish
(少なくともバージョン2.4.0)、execve()
失敗した場合にエラーを返します(スクリプトとして処理しようとしません)。
一部のシェル(bash
またはAT&Tなどksh
)は、最初にファイルがスクリプトである可能性が高いかどうかをヒューリスティックに判断しようとします。そのため、最初の数バイトにNUL文字が含まれていると、一部のシェルがスクリプトの実行を拒否する場合があります。
またexecve()
、ENOEXECで失敗したが、ファイルにシェバン行がある場合、一部のシェルはシェバン行自体を解釈しようとすることに注意してください。
いくつかの例:
- とき
$SHELL
で/bin/bash
、xterm -e 'myscript with args'
きますmyscript
によって解釈bash
でsh
モード。とともにxterm -e myscript with args
、xterm
を使用するexecvp()
ため、スクリプトはによって解釈されsh
ます。
su -c myscript
Solaris 10でどこroot
のログインシェルがある/bin/sh
と/bin/sh
Bourneシェルが持つあるmyscript
Bourneシェルによって解釈します。
/usr/xpg4/bin/awk 'BEGIN{system("myscript")'
Solaris 10では、/usr/xpg4/bin/sh
(と同じ/usr/xpg4/bin/env myscript
)によって解釈されます。
find . -prune -exec myscript {} \;
Solaris 10(を使用execvp()
)では、POSIX環境であっても(適合バグ)/bin/sh
でも解釈され/usr/xpg4/bin/find
ます。
csh -c myscript
csh
で始まる場合#
、sh
それ以外の場合で解釈されます。
全体として、どのスクリプトがどのように呼び出されるのかわからない場合、そのスクリプトを解釈するためにどのシェルが使用されるのかがわかりません。
いずれにせよ、構文read -p
はbash
-onlyなので、スクリプトが解釈されるようにしますbash
(そして、その誤解を招く.sh
拡張子を避けます)。bash
実行可能ファイルのパスを知っており、次のいずれかを使用します。
#! /path/to/bash -
read -p ...
または、次を使用して$PATH
、bash
実行可能ファイル(bash
インストール済みと仮定)のルックアップを試すことができます。
#! /usr/bin/env bash
read -p ...
(env
ほぼどこにでもあります/usr/bin
)。または、POSIX + Bourne互換にすることもできます/bin/sh
。この場合、を使用できます。すべてのシステムにはがあり/bin/sh
ます。それらのほとんどで(ほとんど)POSIXと互換性がありますが、Bourneシェルが代わりに見つかることもあります。
#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"