web-dev-qa-db-ja.com

「/ bin / sh」が「/ bin / bash」を指しているときにシェルスクリプトを実行する

私はこれで以下を読みました 質問

bashは--posixスイッチをサポートしており、POSIXに準拠しています。 がshとして呼び出された場合も、POSIXを模倣しようとします。

上記の引用は、/bin/sh/bin/bashを指すリンクであることを前提としています。

しかし、「shとして呼び出される」の意味がよくわかりません。


「script.sh」と呼ばれる次のスクリプトがあるとします。

#!/bin/bash
echo "Hello World"

スクリプトが通常のbashモードで実行されるのか、POSIXモードで実行されるのかを、次のそれぞれのケースで教えてください(bashを実行している端末で次のコマンドを実行したと想定します) :

  1. sh script.sh
  2. bash script.sh
  3. ./script.sh

「script.sh」と呼ばれる次のスクリプトがあるとしましょう(上記のスクリプトに似ていますが、シバンはありません)。

echo "Hello World"

スクリプトが通常のbashモードで実行されるのか、POSIXモードで実行されるのかを、次のそれぞれのケースで教えてください(bashを実行している端末で次のコマンドを実行したと想定します) :

  1. sh script2.sh
  2. bash script2.sh
  3. ./script2.sh
11
user269904

ケース1と4のみがPOSIXモードで実行されます(shはbashであり、shの他の実装ではないと想定)。シバンからであろうとなかろうと、--posixなしで明示的にbashを呼び出すケースは、実行されません。明示的にshを呼び出すケースはすべて発生します。 Shebangは、シェルがスクリプトに対して明示的に開始されていない場合にのみ使用されます。

ケース6、ターミナルがbashを実行している場合、POSIXモードで実行されず、 Bashはそれ自体を使用して起動します。ターミナルがzshを実行している場合は、ケース6wouldもPOSIXモードで実行されます。POSIXはその場合に何が起こるか正確に不明確です 、そしてBashとzshは異なる選択をしました。 Bashはそれ自体を使用してスクリプトを呼び出し、zshはshを使用します(それが何であれ)。他のシェルもその点で異なります。


現在のモードを確認する簡単な方法の1つは、スクリプトの本文を作成することです。

kill -SIGHUP

これは POSIXモードではエラーで失敗する ですが、その外でのkillの使用方法を示しています。これは簡単に区別でき、遭遇する可能性が高い限り、過去のBashのさまざまなバージョンで機能します。

19
Michael Homer

"invoked as"は、Bashを起動するプロセスが "0番目"のコマンドライン引数_argv[0]_に入れるものを意味します。

exec*() syscalls を使用してプログラムを起動すると、プログラムを含むバイナリファイルの名前を実際に知ることはできませんが、代わりにプロセスは、必要なものを自由に配置できます。もちろん、通常、名前はファイルシステムから取得されます。そのため、_/bin/sh_を実行すると、そこに配置されます。また、_/bin/sh_がBashの場合、シンボリックリンクである必要はありません。ハードリンクまたはシェルプログラムの別のコピーである可能性があります。

「プログラム名」を設定する例として、Bashのexecコマンドは、_-a_オプションを使用してゼロ番目の引数を設定できます。 (Perlで同じことをすることも、Cで直接行うこともできます。)

ここで、mynameは単純なCプログラムであり、0番目の引数を表示します。

_$ ./myname 
I am ./myname
$ (exec -a something ./myname )
I am something
$ mv ./myname somename
$ ln -s somename othername
$ ./somename 
I am ./somename
$ ./othername
I am ./othername
_

ソース:

_#include <stdio.h>
int main(int argc, char *argv[]) {
    printf("I am %s\n", argv[0]);
    return 0;
}
_

しかし、番号の付いた質問に答えるために...

(1&4)_sh somescript_を実行すると、shPATHにあるものすべてが実行されます。おそらく_/bin/sh_ですが、 おそらく_/usr/xpg4/bin/sh_

  • Bashの場合、shという名前が表示されるため、POSIXモードで実行されます。
  • ZシェルまたはKornシェルの場合、同様にshという名前が表示されますが、「SH互換」モードで実行されます。これは、ボーンシェル互換であることを目的としており、完全なPOSIX準拠とは微妙に異なりますこれらのシェルの両方でモード。
  • もちろん、Almquist Shell、実際のBourne Shell、またはその他の何かである可能性があります。

(2&5)_bash somescript_を実行すると、通常のBashモードで実行されます(もちろん、bashPATHが何であるかによって異なります)。

(3)ここでは、スクリプトの名前は、プログラムファイルの代わりにシステムコールに直接指定されます。カーネルはハッシュバン行を読み取り、それを使用してスクリプトを実行します。

(6)これは複雑な問題です。 (3)に似ていますが、プログラムを開始するためのシステムコールは失敗します(ENOEXEC (Exec format error))。ハッシュバング行がないためです。次に何が起こるかは、実行しているシェルがPOSIXモードのitselfであるかどうかによって異なります。 POSIXでは、POSIX準拠のシェルがENOEXECに応答して特定の方法で動作する必要があります。 ただし、「シェルを使用するのと同等のコマンドには、ある程度の余裕があります。呼び出された」は、異なるシェルが異なることを行うことを意味します。

  • Bourne Again Shellは、スクリプトの名前を最初のコマンドライン引数として同じモードで再実行します。もちろん、POSIX準拠モードでは、自身をPOSIX準拠モードで実行しているため、POSIX要件に従ってPOSIX準拠シェルを呼び出すことができます。
  • Zシェル、Almquistシェル、およびKornシェルは、最初のコマンドライン引数として他の引数の前に挿入されたスクリプトの名前を使用して_/bin/sh_を実行します。 Zシェル、Almquistシェル、およびKornシェルは、_/bin/sh_プログラムが1つであると想定して、POSIX準拠のシェルを呼び出すことを試みています。
8
ilkkachu

実行されるシェルはどちらかコマンドラインで呼び出されたシェル、またはシバンで呼び出されたシェル(コマンドラインで指定されていない場合)です。

したがって、バージョン1と4はshで実行され、2と5はbashで実行され、6はnotを実行します(sh(および他のいくつか)をインタラクティブに使用している場合)。 Bashはスクリプトを開始します。 Kshまた。Zshはshとして起動します。

Bashが/bin/shにリンクされている場合、shとして開始されたものだけがposixオプションを使用します。

スクリプトに次の行を追加して、bash kshまたはzshバージョンが実行しているかどうかを検出します。

echo "Hello World $BASH_VERSION $KSH_VERSION $ZSH_VERSION"
4
Isaac