いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

プロセスに適用されている環境変数を調べる

概要

小ネタ。よく忘れるのでメモメモ。知ってるとちょっと便利なもの。

特定の環境変数の値を読み取って動作するプログラムはよくあります。

で、実行してみるとなんか挙動がおかしい。。。ってときがたまにあります。

どうも環境変数の値っぽい感じがするんだけど、プログラムをデバッグのためにいじって再コンパイルすることなどはちょっと無理・・・みたいな状況もたまにあります・・。実環境にgdbも入ってないとかもよくあります。。。

そういうときは、/proc ファイルシステムの プロセステーブル の値を見るのが使えるかもしれません。

/proc の下には現在のプロセス毎にディレクトリが配置されます。

例えば、プロセスIDが1111の場合は /proc/1111 というディレクトリがあります。

この中を見ると、そのプロセスに関する情報がいっぱいあるのですが、プロセス起動時に適用された環境変数のリストが入っている environ という名前のファイルがあります。

このファイルの中身を見ると、プロセスが起動されたときの環境変数が見れます。

注意点として

  • /proc/pid/environ ファイルは ヌル文字 で結合されている

という点があります。改行ではないので、区切り文字を変換してやらないと全部つながってみえちゃいます。

読み取り専用の普通のファイルと同じように扱えますので、cat とかで中身が見えます。

Linux/Unix の「全てはファイルである (Everything is a file)」の思想は素晴らしいですね。

サンプル

同じプログラムを2回起動して、1回目は環境変数指定なし、2回目は環境変数指定ありで起動しています。

#!/usr/bin/env bash

basedirpath=/tmp/try-linux/list_proc_environ

# 実験用のディレクトリ作成
rm -rf "$basedirpath"
mkdir -p "$basedirpath"

# SIGTERMを受け取るまで待機するプログラム
cat << EOF > "$basedirpath"/main.go
package main
import (
    "os"
    "os/signal"
    "syscall"
)
func main() {
    c := make(chan os.Signal, 1)
    signal.Notify(c, syscall.SIGTERM)
    <-c
}
EOF

# プログラムをコンパイル
# ベースディレクトリを動かしたくないのでサブシェル起動して処理
(
    cd "$basedirpath"
    go build -o app main.go
)

#
# 独自の環境変数を追加せずプロセス起動
#
echo '---------- not set ----------'
"$basedirpath"/app >/dev/null 2>&1 &
app1_pid="$!"

# MY_ENV という環境変数は設定していないので何も表示されない
# /proc/pid/environ ファイルのデータは ヌル文字 で結合されていることに注意
tr '\0' '\n' < "/proc/$app1_pid/environ" | grep 'MY_ENV'
kill -SIGTERM "$app1_pid"

#
# 独自の環境変数を追加してプロセス起動
#
echo '----------     set ----------'
MY_ENV='my_env' "$basedirpath"/app >/dev/null 2>&1 &
app2_pid="$!"

# MY_ENV という環境変数を設定しているので表示される
# /proc/pid/environ ファイルのデータは ヌル文字 で結合されていることに注意
tr '\0' '\n' < "/proc/$app2_pid/environ" | grep 'MY_ENV'
kill -SIGTERM "$app2_pid"

# プロセス終了待ち
wait "$app1_pid" "$app2_pid"

try-linux/list_proc_environ.sh at master · devlights/try-linux · GitHub

実行すると以下のようになります。

gitpod /workspace/try-linux $ make
bash ./main.sh -o
ENTER EXAMPLE NAME: proc
[INPUT ] proc
[TARGET] proc_list_proc_environ
[SCRIPT] basic/proc/list_proc_environ.sh
===== START [basic/proc/list_proc_environ.sh] =====
---------- not set ----------
----------     set ----------
MY_ENV=my_env
===== END   [basic/proc/list_proc_environ.sh] =====

参考情報


過去の記事については、以下のページからご参照下さい。

  • いろいろ備忘録日記まとめ

devlights.github.io

サンプルコードは、以下の場所で公開しています。

  • いろいろ備忘録日記サンプルソース置き場

github.com

github.com

github.com