envの出力で確認できる変数を出力できないのはなぜですか?


9

別のシェルインスタンスの環境変数を設定することに興味があります。だから私はいくつかの研究を行うことにしました。これについてのいくつか質問を読んだ後、私はそれをテストすることにしました。

2つのシェルAとB(PID 420)を生成し、どちらもを実行していzshます。シェルAIから以下を実行しました。

sudo gdb -p 420
(gdb) call setenv("FOO", "bar", 1)
(gdb) detach

シェルBから実行するenvと、変数FOOが実際にbarの値で設定されていることがわかります。これにより、シェルBの環境でFOOが正常に初期化されたと思います。ただし、FOOを印刷しようとすると、設定されていないことを示す空の行が表示されます。私には、ここには矛盾があるように感じます。

これは私自身のArch GNU / LinuxシステムとUbuntu VMの両方でテストされました。またbash、変数がenvに表示されない場所でもテストしました。これは私には失望しますが、シェルがスポーン時にその環境のコピーをキャッシュし、それだけを使用する場合は理にかなっています(リンクされた質問の1つで提案されていました)。これはまだzsh変数を見ることができる理由には答えません。

echo $FOO空の出力はなぜですか?


編集

コメントへの入力後、もう少しテストを行うことにしました。結果は以下の表で確認できます。最初の列は、FOO変数が注入されたシェルです。最初の行には、その下に出力を表示できるコマンドが含まれています。変数FOOは次を使用して注入されました:sudo gdb -p 420 -batch -ex 'call setenv("FOO", "bar", 1)'。zsh:に固有のコマンドzsh -c '...'もbashを使用してテストされました。結果は同じであり、簡潔にするためにそれらの出力は省略されました。

Arch GNU / Linux、zsh 5.3.1、bash 4.4.12(1)

|      |  env | grep FOO  | echo $FOO |  zsh -c 'env | grep FOO'  |  zsh -c 'echo $FOO'  |         After export FOO          |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh  |  FOO=bar         |           | FOO=bar                   | bar                  | No Change                         |
| bash |                  | bar       |                           |                      | Value of FOO visible in all tests |

Ubuntu 16.04.2 LTS、zsh 5.1.1、bash 4.3.48(1)

|      |  env | grep FOO  | echo $FOO |  zsh -c 'env | grep FOO'  |  zsh -c 'echo $FOO'  |         After export FOO          |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh  |  FOO=bar         |           | FOO=bar                   | bar                  | No Change                         |
| bash |                  | bar       |                           |                      | Value of FOO visible in all tests |

上記は、結果が分布にとらわれないことを意味するようです。これは、はるかに超える私に教えてくれないzshbash、異なる変数の設定を処理します。さらに、export FOOシェルに応じて、このコンテキストでは動作が大きく異なります。うまくいけば、これらのテストが他の誰かに何かを明確にすることができるでしょう。


zsh -c 'echo $FOO'代わりに(単一引用符を使用!)すると、どうなりますか?見えますか?
user1934428 2017

新しいサブシェルから正しい値が出力されます(bashの子についてもテストされています)。子供がそれを継承できるので、明らかに環境は何とかして永続的ですが、なぜ親はそれを尊重しないのですか?
rlf 2017

3
私もそう思っていました。シェルには変数のシンボルテーブルがどこかにあり、それらの一部は「エクスポート済み」とマークされています。つまり、サブシェルを開くと、子プロセスの環境に配置されます。最初に(シェルの起動時に)、そのときの環境の変数がシンボルテーブルにコピーされます(もちろん、「エクスポートされた」変数としても)。環境を変更しても、シェルはシンボルテーブルを更新するよう通知されませんが、子プロセス(などenv)は変更された環境を参照します。
user1934428 2017

2
zsh 5.1.1とbash 4.3.48(1)を搭載したUbuntu 16.04でテストしました。GDBで環境変数を設定してzshも、シェル変数として表示されないようですが、子プロセスに渡されます(あなたはのための1つ設定しながら、)を観察してきたbash シェル変数としてそれが見えるようにしますがないではない、それは子プロセスに渡すことが原因!zshとbashは変数を管理するために異なる戦略を使用しているようです。zshは非環境変数を追跡し、bashは(非サブシェル)子の起動時にサニタイズする環境内のすべてを保存します。
Eliah Kagan 2017

@EliahKagan、興味深い。それを回答として投稿してください。あなたが走っexport FOOた場合、それは違いを生むのだろうかbash
ワイルドカード2017

回答:


2

ほとんどのシェルはgetenv()/ setenv()/ putenv()APIを使用しません。

起動時に、環境変数ごとにシェル変数を作成します。それらは、変数がエクスポートされるかどうか、読み取り専用などの他の情報を運ぶ必要のある内部構造に保存されます...それらにはlibcを使用できませんenviron

同様に、その理由のために、彼らは使用しませんexeclp()execvp()コマンドを実行するが、呼び出すためにexecve()、コンピューティング、直接システムコールをenvp[]自分のエクスポート変数のリストに基づいて配列を。

したがって、では、gdbシェルの変数の内部テーブルにエントリを追加するか、適切な関数を呼び出して、export VAR=valueコードを解釈してテーブルを更新する必要があります。

あなたは違いを参照してください理由をbashzshあなたが呼び出すときsetenv()gdb、私はあなたが呼んでいるので、それの疑いがsetenv()入ると、たとえば、シェルを初期化する前にmain()

bash's main()is int main(int argc, char* argv[], char* envp[])(およびbashからそれらのenv varsから変数をマップするenvp[])に気づくでしょうが、zsh' s isは代わりに変数int main(int argc, char* argv[])zsh取得しますenvironsetenv()変更environはできますがenvp[]、インプレースは変更できません(いくつかのシステムでは読み取り専用と、これらのポインターが指す文字列)。

いずれの場合でも、environ起動時にシェルが読み取った後は、シェルが後で(または)をsetenv()使用しないため、使用しても効果がありません。environgetenv()

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.