Shebangなしでスクリプトを実行するシェルインタプリタとは何ですか?

Shebangなしでスクリプトを実行するシェルインタプリタとは何ですか?

私のアカウントのデフォルトシェルはzshですが、ターミナルを開き、bashを起動し、というスクリプトを実行するとします。prac002.shzshまたは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/shdashzshまたは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を呼び出します。または他の多くのコマンド(代わりにユーザーのログインシェルを呼び出す)。$SHELLvi!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/shsh/bin/sh

貝殻にはさまざまなバリエーションがあります。bash、AT&T、Bourneシェルは通常、(サブプロセスを使用しない限り)シミュレーション後にスクリプト自体を解釈します。kshつまり、エクスポートされていないすべての変数の設定を解除し、実行時に閉じるfdをすべて閉じて、すべてのカスタムトラップ、エイリアス、関数を削除します... (スクリプトモードで解釈されます)。それを解釈するためにそれ自体が実行されます(モードでそのように使用されます)。execexecve()bashshyashshargv[0]sh

zshpdksh、に基づくシェルがash通常呼び出されますsh(そのパスはコンパイル時に決定されます)。

cshand tcsh(および一部の初期BSD)のsh場合、ファイルの最初の文字があれば#解釈するために自分で実行され、shそれ以外の場合は実行されます。これはcsh実際に#コメントとして認識されたが、Bourneシェルでは認識されていなかったShebang以前の時代にさかのぼります。したがって、#これはcshスクリプトであることを示唆しています。

fish(最小バージョン2.4.0)execve()失敗した場合はエラーのみを返します(スクリプトで処理しようとしません)。

一部のシェル(bashAT&Tkshなど)は、まずファイルがスクリプトであるかどうかを経験的に判断しようとします。したがって、スクリプトの最初の数バイトにNUL文字がある場合、一部のシェルはスクリプトの実行を拒否する可能性があります。

さらに、execve()ENOEXECが失敗したがファイルにshebang行がある場合、一部のシェルはshebang行自体を解釈しようとします。

いくつかの例は次のとおりです。

  • これは in モードに$SHELL解釈され/bin/bashます。そしてusingが使用されるので、スクリプトが解釈されます。xterm -e 'myscript with args'myscriptbashshxterm -e myscript with argsxtermexecvp()sh
  • su -c myscriptrootログインシェルがBourne/bin/shシェルであるSolaris 10では、Bourneシェルが解釈され/bin/shますmyscript
  • /usr/xpg4/bin/awk 'BEGIN{system("myscript")'/usr/xpg4/bin/shSolaris 10では(と同じ)と解釈されます/usr/xpg4/bin/env myscript
  • find . -prune -exec myscript {} \;Solaris 10(使用)では、POSIX環境でもEvenexecvp()と解釈されます(整合性エラー)。/bin/sh/usr/xpg4/bin/find
  • csh -c myscriptcshで始まると、そうでない#と解釈されます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 が指定されていない場合。

関連情報