アカウントのデフォルトのシェルがzshであると仮定しますが、ターミナルを開いてbashを起動し、prac002.sh
という名前のスクリプトを実行しました。このシェルインタープリターを使用して、zshまたはbashのスクリプトを実行します。次の例を検討してください。
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % Sudo cat /etc/passwd | grep papagolf
[Sudo] password for papagolf:
papagolf:x:1000:1001:Rex,,,:/home/papagolf:/usr/bin/zsh
# papagolf's default Shell is zsh
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % bash
# I fired up bash. (See that '%' Prompt in zsh changes to '$' Prompt, indicating bash.)
papagolf@Sierra:~/My Files/My Programs/Learning/Shell$ ./prac002.sh
Enter username : Rex
Rex
# Which interpreter did it just use?
**編集:**スクリプトの内容は次のとおりです
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % cat ./prac002.sh
read -p "Enter username : " uname
echo $uname
スクリプトは_#!
_ Shebang行で始まっていないため、どのインタープリターを使用するかを示しているため、 POSIXはそれを示しています :
execl()
関数が、POSIX.1-2008のシステムインターフェースボリュームで定義されている[ENOEXEC]エラーに相当するエラーのために失敗した場合、シェルは、検索の結果のパス名を最初のオペランドとして使用してシェルを呼び出すのと同等のコマンドを実行します。残りの引数は新しいシェルに渡されますが、「新しいシェルの$ 0 "がコマンド名に設定されている可能性があります。実行可能ファイルがテキストファイルでない場合、シェルはこのコマンドの実行をバイパスする可能性があります。この場合、エラーメッセージを書き込み、終了ステータス126を返します。
その言い回しは少しあいまいで、シェルが異なれば解釈も異なります。
この場合、Bashはそれ自体を使用してスクリプトを実行します。一方、代わりにzshから実行した場合、zshは代わりにsh
(システムにあるものは何でも)を使用します。
このケースの動作を確認するには、スクリプトに次の行を追加します。
_echo $BASH_VERSION
echo $ZSH_VERSION
_
Bashの最初の行はバージョンを出力し、2番目の行は使用するシェルに関係なく何も言わないことに注意してください。
/bin/sh
_がたとえばdash
の場合、スクリプトがzshまたはdashから実行されても、どちらの行も何も出力しません。/bin/sh
_がBashへのリンクである場合、すべてのケースで最初の行の出力が表示されます。/bin/sh
_が直接使用しているものとは異なるバージョンのBashである場合、bashから直接およびzshからスクリプトを実行すると、異なる出力が表示されます。_ps -p $$
_ roolsの回答からのコマンド は、シェルがスクリプトの実行に使用したコマンドに関する有用な情報も表示します。
ファイルはシステムによって認識される実行可能ファイルのタイプではないため、そのファイルを実行する権限があると想定すると、execve()
システムコールは通常ENOEXEC
(実行可能ではありません)エラー。
次に何が起こるかは、コマンドを実行するために使用されるアプリケーションやライブラリ関数次第です。
たとえば、シェル、execlp()
/execvp()
libc関数です。
他のほとんどのアプリケーションは、コマンドを実行するときにこれらのいずれかを使用します。たとえば、system("command line")
libc関数を介してシェルを呼び出し、通常はsh
を呼び出してコマンドラインを解析します(パスはコンパイル時に決定できます(Solarisの/bin/sh
と/usr/xpg4/bin/sh
など))。または、$Shell
コマンドと一緒にvi
のように、!
に格納されているシェルを単独で呼び出すか、xterm -e 'command line'
と他の多くのコマンドを使用します(su user -c
は、$Shell
の代わりにユーザーのログインシェルを呼び出します)。
一般に、#
で始まらないシバンレスのテキストファイルは、sh
スクリプトと見なされます。ただし、どのsh
かは異なります。
execlp()
/execvp()
、execve()
がENOEXEC
を返すと、通常、sh
が呼び出されます。複数のsh
を持つシステムの場合、複数の標準に準拠できるため、sh
は通常、コンパイル時に決定されます(execvp()
/execlp()
を使用するアプリケーションのsh
への異なるパスを参照するコードの異なるblob。たとえば、Solarisでは、/usr/xpg4/bin/sh
(標準、POSIX sh
)または/bin/sh
(Solaris 10以前のBourne Shell(旧式のシェル)、Solaris 11ではksh93)のいずれかになります。
砲弾に関しては、さまざまなバリエーションがあります。 bash
、AT&T ksh
、Bourne Shellは通常、execve()
をシミュレートした後、スクリプト自体を(exec
を使用していない場合は子プロセスで)解釈します。 exec fds、すべてのカスタムトラップ、エイリアス、関数を削除しました(bash
はsh
モードでスクリプトを解釈します)。 yash
はそれ自体を実行し(sh
をargv[0]
としてsh
モードで)解釈して解釈します。
zsh
、pdksh
、ash
ベースのシェルは、通常、sh
(コンパイル時に決定されるパス)を呼び出します。
csh
とtcsh
(および初期のBSDのsh
)の場合、ファイルの最初の文字が#
である場合、それらはそれ自体を実行して解釈し、そうでない場合はsh
を実行します。 csh
が#
をコメントとして認識したがBourne Shellを認識しなかったシェバン前の時代にさかのぼるので、#
は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
によって解釈されます。root
のログインシェルがsu -c myscript
で、/bin/sh
がBourneシェルであるSolaris 10の/bin/sh
は、myscript
がBourneシェルによって解釈されます。/usr/xpg4/bin/awk 'BEGIN{system("myscript")'
は、/usr/xpg4/bin/sh
によって解釈されます(/usr/xpg4/bin/env myscript
と同じ)。find . -Prune -exec myscript {} \;
(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 ...
または、以下を使用して、bash
実行可能ファイルの$PATH
ルックアップ(bash
がインストールされていると想定)に依存して試すこともできます。
#! /usr/bin/env bash
read -p ...
(env
は、ほぼどこでも/usr/bin
にあります)。または、POSIX + Bourne互換にすることもできます。その場合は、/bin/sh
を使用できます。すべてのシステムに/bin/sh
があります。それらのほとんどでは、(ほとんどの場合)POSIX互換ですが、代わりにBourne Shellが時々見つかります。
#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"
ない場合#!
(呼び出されるShebang)行、shが使用されます。これを確認するには、次のスクリプトを実行します。
ps -p $$
echo -n "The real Shell is: "
realpath /proc/$$/exe
私のコンピューターでは
PID TTY TIME CMD
13718 pts/16 00:00:00 sh
The real Shell is: /usr/bin/bash
デフォルトのシェルがzshであっても。私のマシンではshコマンドがbashによって実装されているため、これはbashを使用します。