プロセスが親プロセスの環境を継承する場合、それをエクスポートする必要があるのはなぜですか。

プロセスが親プロセスの環境を継承する場合、それをエクスポートする必要があるのはなぜですか。

私は読んだここシェルの目的exportは、シェルで開始された子プロセスに変数を使用できるようにすることです。

しかし、私も読んだ。ここそしてここそれ「プロセスは親(プロセスを開始したプロセス)から環境を継承します。」

それではなぜ必要なのでしょうかexport?私は何を見逃していますか?

デフォルトでは、シェル変数は環境の一部ではありませんか?違いは何ですか?

答え1

あなたの仮定はシェル変数です環境で。これは正確ではありません。このexportコマンドは環境の名前を定義します。したがって:

a=1 b=2
export b

最新の結果ですシェル$a1と2に拡張されることを知っていますが、子プロセスは環境の一部ではないため(現在のシェルでも)$b何も知りません。a

いくつかの便利なツール:

  • set:現在のシェルのパラメータを表示するために使用されます(エクスポートまたはエクスポートされません)。
  • set -k:セット指定されたパラメータ環境で。考えるf() { set -k; env; }; f a=1
  • set -a:環境に設定された名前を入力するようにシェルに指示します。exportすべてのミッション前と同様に。のようなファイルに.env便利ですset -a; . .env; set +a
  • export:環境に名前を入力するようにシェルに指示します。エクスポートと割り当てはまったく異なる操作です。
  • env:外部コマンドとして、env次の事項のみを通知できます。遺伝学したがって、完全性検査に役立ちます。
  • env -i: 子プロセスを開始する前に環境を整理するのに役立ちます。

代替計画export:

  1. name=val command#コマンドの前に割り当てると、名前がコマンドとしてエクスポートされます。
  2. declare/local -x name# 名前をエクスポートします。特に、名前が外部スコープに公開されないようにする場合は、シェル関数に役立ちます。
  3. set -a#次の各ジョブをエクスポートします。

やる気

では、なぜシェルには独自の異なる変数と環境が必要なのですか?もちろん、いくつかの歴史的な理由があると確信していますが、主な理由は範囲指定のためだと思います。この環境は子プロセス用ですが、子プロセスをフォークしなくてもシェルで多くの操作を実行できます。ループを繰り返すとしましょう。

for i in {0..50}; do
    somecommand
done

somecommandを含むi環境を必要以上に大きくしてメモリを無駄にするのはなぜですか?シェルで選択した変数名がプログラムが意図しないことを意味する場合はどうなりますか? (私が個人的に好きな名前にはDEBUG.とがありますVERBOSE。これらの名前はどこにいても名前空間はほとんどありません。)

シェルでなければどのような環境ですか?

時々、Unixの動作を理解するためにカーネルやオペレーティングシステムと対話するための基本的なAPIであるシステムコールを見てください。ここでは、exec子プロセスを作成するときにシェルで使用される一連の呼び出しを見てみましょう。これはから来たものですマンページexec(3)(強調):

execle()関数を使用すると、execvpe()呼び出し側はenvpパラメーターを介してプログラムが実行される環境を指定できます。 envpパラメーターは、NULLで終わる文字列へのポインター配列であり、NULLポインターで終わる必要があります。他の関数は、呼び出しプロセスの外部変数environから新しいプロセスイメージの環境を取得します。

したがって、シェルに書き込むことは、Cのグローバル辞書export somenameに名前をコピーするのと同じです。environただし、somenameエクスポートせずに割り当てるのは、Cから変数にコピーせずに割り当てるのと同じですenviron

答え2

シェル変数と環境変数には違いがあります。シェル変数を指定せずに定義すると、exportその変数はプロセス環境に追加されず、その子プロセスに継承されません。

export環境に追加するようにシェルに指示したシェル変数を使用します。以下を使用してテストできます。printenv(環境を に印刷してstdoutサブプロセスなのでexporting 変数の効果を見ることができます。)

#!/bin/sh

MYVAR="my cool variable"

echo "Without export:"
printenv | grep MYVAR

echo "With export:"
export MYVAR
printenv | grep MYVAR

答え3

変数をエクスポートすると、その変数は環境の一部になります。PATHシェル自体からエクスポートでき、必要に応じてカスタム変数をエクスポートできます。いくつかの設定コードを使用してください。

$ cat subshell.sh 
#!/usr/bin/env bash
declare | grep -e '^PATH=' -e '^foo='

比較する

$ cat test.sh 
#!/usr/bin/env bash
export PATH=/bin
export foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test.sh 
PATH=/bin
foo=bar
PATH=/bin
foo=bar

そして

$ cat test2.sh 
#!/usr/bin/env bash
PATH=/bin
foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test2.sh 
PATH=/bin
foo=bar
PATH=/bin

fooシェルからエクスポートしたことがなく、エクスポートされたことがないため、最後の実行環境の一部ではtest2.shありません。subshell.sh

答え4

簡単に言うと:

  • プロセスは親プロセスから環境変数を継承します。
  • Bashでは、$ a = 1は環境変数ではなく「一般」変数を生成します。
  • エクスポートa = 1はターミナルプロセスの環境変数を生成します(他の方法があります)
  • 環境データを子プロセスに渡す他の方法はありますか?

関連情報