Unixの別のプロセスの環境変数を変更する方法はありますか?


105

Unixで、あるプロセスが別のプロセスの環境変数を変更できる方法はありますか(それらがすべて同じユーザーによって実行されていると想定)。一般的な解決策が最善ですが、そうでない場合、一方が他方の子である特定のケースについてはどうでしょうか?

編集:gdbはどうですか?


これは私に醜い印象を与えます。解決したい実際の問題は何ですか?
Jens

1
例:UIによって起動されるすべての新しいアプリが環境変数を取得できるように、環境変数を定義したいと思います。起動スクリプトとRE-LOGINの1つで変数を定義する以外の方法は知りません。ただし、再ログインせずに、現在のセッションで変数を定義して、新しいアプリがUIからログアウトせずに取得できるようにします。
AlikElzin-kilaka 2012

回答:


142

gdb経由:

(gdb) attach process_id

(gdb) call putenv ("env_var_name=env_var_value")

(gdb) detach

これは非常に厄介なハックであり、もちろんデバッグシナリオのコンテキストでのみ実行する必要があります。


8
したがって、GDBのようにプロセスにアタッチしてからデタッチすると、実際にプロセスの環境を変更できることを意味しているようです。これだけを行うプログラムを書くことは可能だろう。
悲しむ

3
「これだけを行うプログラムを書くことは可能だろう」確かにそうだ。
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

2
cygwinを使用してコンパイルされていないプロセスの場合、cygwinを使用してWindowsでも動作します!
ファンカルロスムニョス

11
これが機能するのは、前のgetenvの後でプロセスが値を永続的にキャッシュしていない場合のみです。
Anddrew 2013年

1
ptrace: Operation not permitted
gerrit 2014年

22

あなたはおそらく技術的にそれを行うことができますが(他の回答を参照)、それはあなたを助けにはしないかもしれません。

ほとんどのプログラムは、起動後にenv変数を外部から変更できないことを想定しているため、起動時に関心のある変数を読み取り、それに基づいて初期化するだけです。したがって、後で変更しても、プログラムがそれらを再度読み取ることはないため、違いはありません。

これを具体的な問題として投稿した場合は、おそらく別のアプローチを取る必要があります。それが好奇心から外れた場合:いい質問:-)。


1
たとえば、新しい端末で新しい変数を使用させたいデスクトップ環境などで、子プロセスに新しい環境変数を継承させるのが最も一般的な使用例です。
Hjulle 2018

13

実質的にはありません。十分な権限(rootまたはその周辺)があり、/ dev / kmem(カーネルメモリ)を突っ込んで、プロセスの環境に変更を加えた場合、およびプロセスが後で実際に環境変数を再参照した場合(つまり、プロセスenv varのコピーをまだ取得しておらず、そのコピーだけを使用していなかった場合)、おそらく、運がよくて賢く、風が正しい方向に吹いていて、月の位相が正しかった場合、あなたは何かを達成するかもしれません。


2
答えがわかりませんでした。
AlikElzin-kilaka 2012

@kilaka:キーワードは2番目のキーワードです— いいえ。残りの答えは、root権限を持っているか、デバッガーを実行している場合は実行できるということですが、実際には、答えはNoです。
ジョナサンレフラー

シェルスクリプトを実行しています。シェルスクリプトの親プロセスの環境を変更したいので、シェルスクリプトgdbは親プロセスで起動し、スクリプトを実行して変更を行い、親プロセスをクラッシュさせることなく機能します。OK —おそらくそれは可能ですが、日常的に行うことではありません。したがって、実際的な目的では、答えはNoのままです。残りの答えは、理論的には可能で、やや非現実的に実行可能な代替策をカバーしています。
ジョナサンレフラー

7

ジェリー・ピークの引用:

古い犬に新しいトリックを教えることはできません。

あなたができる唯一のことは、それを開始する前に子プロセスの環境変数を変更することです:親環境のコピーを取得します、申し訳ありません。

詳細については、http://www.unix.com.ua/orelly/unix/upt/ch06_02.htmを参照してください。

/ procの使用に関する回答についてのコメント。Linuxでは/ procがサポートされていますが、rootであってもファイル変更できません/proc/${pid}/environ。これは完全に読み取り専用です。


どちらがまだ問題を残します:env var値は実際にどこに保存されますか?それはカーネルによって行われますか?または、シェルは値を格納し、/ proc / <pid> / environはそこから値を取得しますか?
オリバー2008年

これは実装の詳細であり、(別の)良い質問になる可能性があります。すべてのUNIXは独自の方法でストレージを使用していると思いますが、それらはすべて、仕様の一部である上記の動作を共有しています。
Davide

7

私はそれを行うためにかなり工夫された方法を考えることができ、それは任意のプロセスでは機能しません。

'char * getenv'を実装する独自の共有ライブラリを作成するとします。次に、「LD_PRELOAD」または「LD_LIBRARY_PATH」環境を設定します。両方のプロセスが共有ライブラリをプリロードして実行されるように、vars。

このようにして、基本的に「getenv」関数のコードを制御できます。次に、あらゆる種類の厄介なトリックを実行できます。「getenv」は、環境変数の代替値について外部設定ファイルまたはSHMセグメントを調べることができます。または、要求された値に対して正規表現検索/置換を行うことができます。または...

動的リンカー(ld-linux.so)を書き直さない限り、(rootであっても)任意の実行中のプロセスに対してこれを行う簡単な方法は考えられません。


これはできるはずです。var = valueペア用の小さなgdbmデータベースを作成できます。私はstromberg.dnsalias.org/~strombrg/malloc-wrapper
dstromberg

しかし、この方法には先見性が必要だと思います。また、誤って多くのプロセスに適用しないように注意する必要があります。
dstromberg

3

または、プロセスに新しいプロセスの構成ファイルを更新させ、次のいずれかを実行します。

  • 新しいプロセスでkill -HUPを実行して、更新された構成ファイルを再度読み取る、または
  • プロセスに時々アップデートの設定ファイルをチェックしてもらいます。変更が見つかった場合は、構成ファイルを再度読み取ります。

2

私の知る限りではありません。実際には、IPCメソッド(共有メモリ、セマフォ、ソケットなど)の1つを呼び出すプロセス間で通信しようとしています。これらの方法のいずれかでデータを受け取ったら、環境変数を設定したり、他のアクションをより直接的に実行したりできます。


1

unixが/ procファイルシステムをサポートしている場合は、envを読み取るのは簡単です。所有しているプロセスの環境、コマンドライン、およびその他の多くの属性を読み取ることができます。それを変える...まあ、私は方法を考えることができますが、それは悪い考えです。

より一般的なケース...わかりませんが、移植性のある答えがあるとは思えません。

(編集:私の元の答えは、OPが環境を変更するのではなく、読み取りたいと想定していた)


おっと、私の回答を編集しました-彼は環境を変更したくないので、環境を読みたいと思っていました。
Mike G.

1
私をぶら下げたままにしないでください。あなたの悪い考えは何ですか?
ラルディ2008年

Linuxでは、あなたが/ proc / <pid> / memをあなたが所有する他のプロセスのために読み書き可能にできるかもしれないと私は信じています...しかし、私にはわかりません。試し、実際に環境をいじることは、間違いなく悪い考えです。私が示唆されていないよだから...それを試してみてください
マイク・G.

1

UNIXはプロセス間通信でいっぱいです。ターゲットインスタンスにいくつかあるかどうかを確認します。Dbusは「デスクトップ」IPCの標準になりつつあります。

awesome-clientを使用してAwesomeウィンドウマネージャー内の環境変数を変更します。luaコードはDbusの「送信者」です。


1

直接的な回答ではありませんが... Raymond Chenはこれについて[Windowsベースの]理論的根拠がありました:-

...確かに、サポートされていない方法やデバッガーの助けを借りて機能する方法はありますが、別のプロセスのコマンドラインへのプログラムによるアクセスについてサポートされているものはなく、少なくともカーネルによって提供されているものはありません。...

ないということは、必要のない情報を追跡しないという原則の結果です。カーネルは別のプロセスのコマンドラインを取得する必要はありません。CreateProcess関数に渡されたコマンドラインGetCommandLineを取得し、関数が取得できる場所にある起動中のプロセスのアドレススペースにコピーします。プロセスが独自のコマンドラインにアクセスできるようになると、カーネルの役割が完了します。

コマンドラインはプロセスのアドレス空間にコピーされるため、プロセスはコマンドラインを保持しているメモリに書き込み、それを変更することもできます。その場合、元のコマンドラインは永久に失われます。既知の唯一のコピーが上書きされました。

つまり、そのようなカーネル機能は

  • 実装が難しい
  • 潜在的にセキュリティ上の懸念

ただし、最も可能性が高い理由は、そのような機能の使用例が限られていることです。


1

putenvは現在動作していないようですが、setenvは動作しています。私は現在のシェルで変数を設定しようとしている間に成功した答えをテストしていました

$] sudo gdb -p $$
(gdb) call putenv("TEST=1234")
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x0
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=

バリアントの仕組み:

$] sudo gdb -p $$
(gdb) call (int) setenv("TEST", "1234", 1)
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x55f19ff5edc0 "1234"
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=1234
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.