Linux /proc/<pid>/environ
は更新されません(私が理解しているように、ファイルにはプロセスの初期環境が含まれています)。
プロセスの現在の環境を読み取るにはどうすればよいですか?
Linux /proc/<pid>/environ
は更新されません(私が理解しているように、ファイルにはプロセスの初期環境が含まれています)。
プロセスの現在の環境を読み取るにはどうすればよいですか?
回答:
/proc/$pid/environ
プロセスが独自の環境を変更した場合に更新します。しかし、多くのプログラムは少し無意味であるため、独自の環境を変更することはありません:プログラムの環境は通常のチャネルでは見えず、とのみで/proc
ありps
、すべてのUNIXバリアントがこのような機能を持っているわけではないため、アプリケーションは依存しませんその上。
カーネルに関する限り、環境execve
はプログラムを起動するシステムコールの引数としてのみ表示されます。Linuxはを通じてメモリ内の領域を公開し、/proc
一部のプログラムはこの領域を更新しますが、他のプログラムは更新しません。特に、この領域を更新するシェルはないと思います。エリアのサイズは固定されているため、新しい変数を追加したり、値の長さを変更したりすることはできません。
PATH=foo
がシェルで書いたからといって、シェルが変更しようとしているわけではありません*envp
。一部のシェルでは、内部データ構造のみが更新され、更新されるのは外部プログラム実行コードです*envp
。見てくださいassign_in_env
でvariables.c
、たとえば、bashのソースで。
fork
libcはsys_fork
、子プロセスに割り当てられたヒープ環境を使用して呼び出しを行います。
argv
はより一般的ですが、両方とも存在します)。
プロセスの初期環境はから読むことができます/proc/<pid>/environ
。
プロセスがその環境を変更する場合、環境を読み取るには、プロセスのシンボルテーブルが必要であり、ptrace
システムコールを使用して(たとえば、を使用してgdb
)グローバルchar **__environ
変数から環境を読み取る必要があります。実行中のLinuxプロセスから変数の値を取得する他の方法はありません。
それが答えです。次に、いくつかの注意事項について説明します。
上記は、プロセスがPOSIX準拠であると想定しています。つまり、プロセスはRef Specでchar **__environ
指定されたグローバル変数を使用して環境を管理します。
プロセスの初期環境は、プロセスのスタック上の固定長バッファーでプロセスに渡されます。(これを行う通常のメカニズムはlinux//fs/exec.c:do_execve_common(...)
。)バッファーのサイズは初期環境に必要なサイズ以下になるように計算されるため、既存の変数を消去したりスタックを破壊したりせずに新しい変数を追加することはできません。したがって、プロセスの環境の変更を許可する合理的なスキームはヒープを使用します。ヒープでは、任意のサイズのメモリを割り当てたり、解放したりできます。これはまさにGNU libc
(glibc
)が行うことです。
プロセスがを使用する場合、glibc
POSIX準拠__environ
ですglibc//posix/environ.c
。Glibc で宣言されると、プロセスのヒープからの__environ
メモリへのポインターで初期化さmalloc
れ、スタックからこのヒープ領域に初期環境がコピーされます。プロセスが使用する各時間setenv
関数は、glibc
ないrealloc
こと領域の大きさを調整する__environ
ポイントに新しい値または変数を収容するために。(glibcのソースコードはでダウンロードできますgit clone git://sourceware.org/git/glibc.git glibc
)。メカニズムを本当に理解するには、Hurdコードhurd//init/init.c:frob_kernel_process()
(git clone git://git.sv.gnu.org/hurd/hurd.git hurd)を読む必要もあります。
新しいプロセスが専用の場合は今fork
編、後続がなくて、exec
スタックを上書きし、その後、引数と環境のコピー魔法がで行われているlinux//kernel/fork.c:do_fork(...)
場合は、copy_process
ルーチン呼び出しdup_task_struct
呼び出して新しいプロセスのスタックを割り当てalloc_thread_info_node
、呼び出しsetup_thread_stack
(linux//include/linux/sched.h
新しいプロセス用)を使用しますalloc_thread_info_node
。
最後に、POSIX __environ
規則はユーザー空間の規則です。Linuxカーネルには何も接続されていません。グローバルを使用glibc
せずに__environ
グローバル変数を使用せずにユーザー空間プログラムを作成し、環境変数を自由に管理できます。これを行うことで誰もあなたを逮捕することはできませんが、独自の環境管理機能(setenv
/ getenv
)と独自のラッパーを作成sys_exec
する必要があり、環境に変更を加えた場所を誰も推測できないでしょう。
/proc/[pid]/
奇妙なエンコーディングを持っているようです(他の誰かが何を、なぜ知っているかもしれません)。私にとってはcat environ
、環境変数を非常に読みにくい形式で出力するだけです。 cat environ | strings
私のためにこれを解決しました。
プロセスが環境変数を取得/削除するときに更新されます。environ
/ procファイルシステムの下のプロセスディレクトリで、プロセスのファイルが更新されていないことを示すリファレンスがありますか?
xargs --null --max-args=1 echo < /proc/self/environ
または
xargs --null --max-args=1 echo < /proc/<pid>/environ
または
ps e -p <pid>
上記は、プロセスの環境変数をps
出力形式で出力します。環境変数をリストとして表示するには、テキスト処理(解析/フィルタリング)が必要です。
Solaris(質問はありませんが、参考のためにここに投稿します):
/usr/ucb/ps -wwwe <pid>
または
pargs -e <pid>
編集: / proc / pid / environは更新されません!私は立ち直る。検証プロセスは次のとおりです。ただし、プロセスの分岐元の子はプロセス環境変数を継承し、それぞれの/ proc / self / environファイルに表示されます。(文字列を使用)
with the shell:ここで、xargsは子プロセスであるため、環境変数を継承し、その/proc/self/environ
ファイルにも反映されます。
[centos@centos t]$ printenv | grep MASK
[centos@centos t]$ export MASK=NIKHIL
[centos@centos t]$ printenv | grep MASK
MASK=NIKHIL
[centos@centos t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK
MASK=NIKHIL
[centos@centos t]$ unset MASK
[centos@centos t]$ printenv | grep MASK
[centos@centos t]$ xargs --null --max-args=1 echo < /proc/self/environ | grep MASK
[centos@centos t]$
ターミナル/セッションが環境変数が設定されているシェルの子プロセスではない他のセッションからチェックします。
同じホスト上の別の端末/セッションから確認する:
terminal1:: printenvはフォークされ、bashの子プロセスであるため、独自のenvironファイルを読み取ることに注意してください。
[centos@centos t]$ echo $$
2610
[centos@centos t]$ export SPIDEY=NIKHIL
[centos@centos t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[centos@centos t]$
terminal2:同じホストで-上記の変数が設定された同じシェルで起動しないで、ターミナルを個別に起動します。
[centos@centos ~]$ echo $$
4436
[centos@centos ~]$ xargs --null --max-args=1 echo < /proc/self/environ | grep -i spidey
[centos@centos ~]$ strings -f /proc/2610/environ | grep -i spidey
[centos@centos ~]$ xargs --null --max-args=1 echo < /proc/2610/environ | grep -i spidey
[centos@centos ~]$
export foo=bar
1つのbashののセッション(PID XXXX)で、その後、行うcat /proc/xxxx/environ | tr \\0 \\n
他のbashのセッションでは、私は表示されませんfoo
。
gdb
pidをアタッチする環境をチェックしようとしましたが、まだ参照がありません。メモリ内の環境変数ブロックは、変更があるたびに再割り当てされ、procファイルシステム内の独自のプロセスの環境ファイルに反映されませんが、子プロセスによる継承は許可されます。つまり、これにより、フォークが発生したときに固有の詳細を簡単に知ることができ、子プロセスが環境変数をそのままコピーする方法がわかります。
まあ、次は著者の本当の意図とは関係ありませんが、あなたが本当に「読む」こと/proc/<pid>/environ
を望むなら、あなたは試みるかもしれません
strings /proc/<pid>/environ
それはcat
それよりも優れています。
strings
。複雑にしないでおく。
xargs --null
ます。
tr '\0' '\n' < /proc/$$/environ | ...