私のアカウントのデフォルトシェルは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
答え1
どのインタプリタを使用するかを示すためにスクリプトが#!
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でスクリプトを実行すると、両方の行は何も出力されません。 - Bashに接続すると、
/bin/sh
すべての場合に最初の出力行が表示されます。 - もし
/bin/sh
あればその他のバージョンBash を直接使用する場合と bash と zsh から直接スクリプトを実行すると、他の出力が表示されます。
これps -p $$
ロール回答のコマンドスクリプトを実行するためにシェルが使用するコマンドに関する有用な情報も表示されます。
答え2
ファイルはシステムによって認識される実行可能ファイルの種類ではなく、ユーザーにファイル実行権限があると仮定すると、システムコールは通常次のようにexecve()
失敗しますENOEXEC
。実行ファイルではありません)間違い。
次のことは、コマンドの実行に使用されるアプリケーションおよび/またはライブラリの機能によって異なります。
execlp()
たとえば、シェル、/ libc関数ですexecvp()
。
他のほとんどのアプリケーションは、コマンドの実行時にこれらのいずれかを使用します。たとえば、コマンドラインを解析するためにsystem("command line")
一般的に呼び出されるlibc関数を介してシェルを呼び出すか(sh
パスはコンパイル時に決定されます(たとえば、Solarisの場合/bin/sh
))、/usr/xpg4/bin/sh
を呼び出します。または他の多くのコマンド(代わりにユーザーのログインシェルを呼び出す)。$SHELL
vi
!
xterm -e 'command line'
su user -c
$SHELL
通常、起動しないshebang-lessテキストファイルはスクリプト#
と見なされますsh
。しかし、具体的な状況はsh
さまざまです。
execlp()
/ execvp()
、通常はexecve()
戻り時にENOEXEC
呼び出されますsh
。複数の標準を使用するシステムでは、複数の標準に準拠する可能性があるため、これは通常sh
コンパイル時sh
に決定されます(アプリケーションは異なるパスを参照する他のコードブロックをリンクして使用execvp()
/リンクします)。たとえば、Solarisでは(標準、POSIX)、(Solaris 10以前ではBourneシェル(古いシェル)、Solaris 11ではksh93)になります。execlp()
sh
/usr/xpg4/bin/sh
sh
/bin/sh
貝殻にはさまざまなバリエーションがあります。bash
、AT&T、Bourneシェルは通常、(サブプロセスを使用しない限り)シミュレーション後にスクリプト自体を解釈します。ksh
つまり、エクスポートされていないすべての変数の設定を解除し、実行時に閉じるfdをすべて閉じて、すべてのカスタムトラップ、エイリアス、関数を削除します... (スクリプトモードで解釈されます)。それを解釈するためにそれ自体が実行されます(モードでそのように使用されます)。exec
execve()
bash
sh
yash
sh
argv[0]
sh
zsh
pdksh
、に基づくシェルがash
通常呼び出されますsh
(そのパスはコンパイル時に決定されます)。
csh
and tcsh
(および一部の初期BSD)のsh
場合、ファイルの最初の文字があれば#
解釈するために自分で実行され、sh
それ以外の場合は実行されます。これはcsh
実際に#
コメントとして認識されたが、Bourneシェルでは認識されていなかったShebang以前の時代にさかのぼります。したがって、#
これはcshスクリプトであることを示唆しています。
fish
(最小バージョン2.4.0)execve()
失敗した場合はエラーのみを返します(スクリプトで処理しようとしません)。
一部のシェル(bash
AT&Tksh
など)は、まずファイルがスクリプトであるかどうかを経験的に判断しようとします。したがって、スクリプトの最初の数バイトにNUL文字がある場合、一部のシェルはスクリプトの実行を拒否する可能性があります。
さらに、execve()
ENOEXECが失敗したがファイルにshebang行がある場合、一部のシェルはshebang行自体を解釈しようとします。
いくつかの例は次のとおりです。
- これは in モードに
$SHELL
解釈され/bin/bash
ます。そしてusingが使用されるので、スクリプトが解釈されます。xterm -e 'myscript with args'
myscript
bash
sh
xterm -e myscript with args
xterm
execvp()
sh
su -c myscript
root
ログインシェルがBourne/bin/sh
シェルであるSolaris 10では、Bourneシェルが解釈され/bin/sh
ますmyscript
。/usr/xpg4/bin/awk 'BEGIN{system("myscript")'
/usr/xpg4/bin/sh
Solaris 10では(と同じ)と解釈されます/usr/xpg4/bin/env myscript
。find . -prune -exec myscript {} \;
Solaris 10(使用)では、POSIX環境でもEvenexecvp()
と解釈されます(整合性エラー)。/bin/sh
/usr/xpg4/bin/find
csh -c myscript
csh
で始まると、そうでない#
と解釈されますsh
。
要約すると、スクリプトがどのように呼び出されているのかわからない場合は、スクリプトを解釈するためにどのシェルを使用するかを判断できません。
とにかくread -p
これは単なるbash
構文であるため、スクリプトが解釈されていることを確認する必要があります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
#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"
答え3
どのシェルが使用されているかを確認するには、次のスクリプトを実行できます。
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
私のデフォルトシェル扱いにくい。それを使う強く打つ私のコンピュータではシェンコマンドは次のように実装されます。強く打つそして扱いにくいおすすめシェンshebang が指定されていない場合。