サブシェルで変数が表示されるのはなぜですか?


18

Learning Bash Bookでは、サブシェルは環境変数とファイル記述子などのみを継承し、エクスポートされない変数は継承しないと述べています。

$ var=15
$ (echo $var)
15
$ ./file # this file include the same command echo $var

$

私が知っているようにシェルがために2つのサブシェルが作成されます()とのために./file、なぜに()ケースを識別サブシェルんvarそれはエクスポートされませんが、変数をし、中./fileケース、それはそれを識別しませんでしたか?

# Strace for () 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25617
# Strace for ./file
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25631

私が使用しようとstrace、この問題が発生したかを把握すると、驚くほど私はbashがクローンシステムコールのために同じ引数を使用します見つけ、中にフォークプロセスの両方、この手段はそう()./file、親の同じプロセスアドレス空間を持つ必要があり、なぜこの()場合、変数はサブシェルに表示され./file、同じ引数はクローンシステムコールに基づいていますが、同じことはケースに起こりませんか?


vinc17は、サブシェルがあるときにpstreeを取得したとしても、この問題を信じています。
ペルシャ湾14

回答:


15

Learning Bash Bookは間違っています。サブシェルはすべての変数を継承します。偶数$$(オリジナルシェルのPID)が維持されます。その理由は、(あなたが入力すると、逆にサブシェル、シェルだけでフォークのために、新たなシェルを実行していないということです./file例えば、新しいシェル、新しいコマンドが実行され、straceの出力で、見execveと似ています) 。したがって、基本的には、単なるコピーです(いくつかの文書化された相違点があります)。

注:これはbashに固有のものではありません。これはすべてのシェルに当てはまります。


わかりましたが、今シェルでstraceを実行しようとし、。/ fileを実行しようとしましたが、execの呼び出しが見つからないため、アドレス空間は両方のプロセスで同じである必要があります。
user3718463 14

@ user3718463 子もトレースする-fオプションを使用しましたstraceか?execを見つけるために必要です。
vinc17 14

うん私は、-fオプションがありませんでした、たくさんの感謝からそれを理解し、私は、exec sysのコールを見つけることができませんので
user3718463

16

あなたまたは本のどちらかが、サブシェルをシェルであるサブプロセスと混同しています。

一部のシェル構成では、シェルが子プロセスをフォークします。Linuxでは、ログで確認したforkより一般的なcloneシステムコールの特殊なケースですstrace。子はシェルスクリプトの一部を実行します。子プロセスはサブシェルと呼ばれます。最も直接的ような構築物はあるcommand1 &command1親シェルで実行するサブシェルで実行され、以降のコマンド。サブシェルを作成するその他の構造には、コマンド置換$(command2)とパイプが含まれますcommand3 | command4command3サブシェルでcommand4実行、ほとんどのシェルではサブシェルで実行されますが、kshまたはzsh では実行されません)。

サブシェルは親プロセスのコピーであるため、同じ環境変数だけでなく、すべて同じ内部定義(変数($$元のシェルプロセスのプロセスID を含む)、関数、エイリアス、オプションなど)もあります。サブシェルでコードを実行する前に、bashは変数BASHPIDを子プロセスのプロセスIDに設定します。

を実行./fileすると、外部コマンドが実行されます。まず、シェルは子プロセスをフォークします。次に、この子プロセスexecveシステム呼び出しで)実行可能ファイルを実行します./file。子プロセスは、親のプロセス属性を継承します:環境、現在のディレクトリなど。アプリケーションの内部的な側面はexecve呼び出しで失われます。エクスポートされていない変数、関数などは、カーネルが知らないbashの概念です。 bashが別のプログラムを実行すると失われます。他のプログラムがたまたまbashスクリプトであったとしても、親プロセスもbashのインスタンスであることを知らないか気にしないbashの新しいインスタンスによって実行されます。したがって、シェル変数(エクスポートされない変数)は存続しませんexecve


この答えは私にとって非常に多くのことを解決しました。私が理解できない唯一のことは、2番目の段落の次の文です。「子はシェルスクリプトの一部を実行します。」どのシェルスクリプトが参照されていますか?
flow2k

@ flow2kシェルが解釈しているスクリプト(プログラム)。
ジル 'SO-悪であるのをやめる'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.