はじめに
ネット上には、プロセスIDからプロセスの環境変数を得る方法として以下の例があります。
(strings部分はsedだったり、trだったり色々だけど、そこは関係ないのです)
$ strings /proc/$pid/environ
好奇心から自分自身の環境変数を取得しようとしたら、設定したはずの環境変数が見当たりません。
$ export rabbit=peter
$ env | grep ^rabbit
rabbit=peter
$ strings /proc/$$/environ | grep ^rabbit
# (TωT)出てこない
自分自身の環境変数ならばenv
(cshならsetenv
)取れるので支障はありません。
問題は、これが自分自身だから駄目だったのか、根本的に/proc/$pid/environ
から得られるものの認識を間違っているのかが分からないと、/proc/$pid/environ
の情報を有効に扱えないことです。
これを調べて、ほぼコレという理由を見つけたので、まとめます。
検証環境
CentOS 7.4.1708上のbash
理由
この方法では、そのプロセスで設定された環境変数は取得できません。
/proc/$pid/environ
で見る事ができるのは、プロセスの初期環境だからです。
新しく環境変数を設定してもプロセスの初期環境を変更しません。なので、/proc/$$/environ
のように自分自身のプロセスIDに対して読み出すと、新しく設定した環境変数を見つけることはできません。
子プロセスを生成する際に子プロセスの初期環境として、自身の初期環境と、新しく設定した環境変数(優先)が引き継がれます。
上記の理由から、プロセスIDから任意のプロセスの全ての環境変数を得る方法はありません。
検証手順
#環境変数を設定する
$ export rabbit=peter
#確認する => 見つからない
$ strings /proc/$$/environ | grep ^rabbit
#子プロセス(サブシェル)を生成する
$ bash
#確認する => 親プロセスで設定された値
$ strings /proc/$$/environ | grep ^rabbit
rabbit=peter
#引き継いだ環境変数を変更する
export rabbit=sekine
#確認する => 親プロセスで設定された値のまま
$ strings /proc/$$/environ | grep ^rabbit
rabbit=peter
#孫プロセス(サブシェル)生成する
bash
#確認する => 子プロセスで設定された値
$ strings /proc/$$/environ | grep ^rabbit
rabbit=sekine
#プロセスの階層を確認
$ ps x --forest
PID TTY STAT TIME COMMAND
5466 ? S 0:00 sshd: vagrant@pts/0
5467 pts/0 Ss 0:00 \_ -bash
5543 pts/0 S 0:00 \_ bash
5565 pts/0 S 0:00 \_ bash
5584 pts/0 R+ 0:00 \_ ps x --forest
#それぞれのプロセスIDを指定して環境変数を取得する
# 親プロセス = 出力なし
$ strings /proc/5467/environ | grep ^rabbit
# 子プロセス = 親プロセスで設定された値
$ strings /proc/5543/environ | grep ^rabbit
rabbit=peter
# 孫プロセス = 子プロセスで設定された値
$ strings /proc/5565/environ | grep ^rabbit
rabbit=sekine
例外
調べたいプロセスが、環境を引き継ぐ条件で生成した子プロセスを持っているならば、/proc/子プロセスのpid/environ
により、引き継いだ初期環境を得られます。
子プロセスが引き継いだ初期環境が親プロセスの環境なので、条件付きならば任意のプロセスの環境変数を取得できます。
まとめ
任意のプロセスIDの環境変数を取得するために/proc/$pid/environ
を参照する場合、その内容は初期環境なので注意が必要ということです。
今回の内容は、unix.stackexchange.comのHow to read environment variables of a processで、Toby Speightさんの回答から理由が分かりました。回答には実装についての説明まであるので、時間を取って実装確認するべきか・・・