/proc と /dev:仮想ファイルシステムを Python から読む

Linux の /proc/dev は実際のディスク上にデータを持たない「仮想ファイルシステム」だ。Python からこれらを読み書きすることで、カーネルの情報を取得したり、デバイスを操作したりできる。

/proc:カーネル情報への窓

/proc はプロセスとカーネルの情報を公開する仮想ファイルシステムだ。ファイルを読むと、その瞬間のカーネルの状態が返される。

# CPU 情報を読む
with open("/proc/cpuinfo") as f:
    for line in f:
        if line.startswith("model name"):
            print(line.strip())
            break
# model name : Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz

# メモリ情報を読む
with open("/proc/meminfo") as f:
    for line in f:
        if line.startswith(("MemTotal", "MemFree", "MemAvailable")):
            print(line.strip())

これらのファイルは実際にはディスク上に存在せず、読み取り時にカーネルが動的に生成する。

/proc/[pid]:プロセスごとの情報

各プロセスは /proc/[pid]/ 以下に専用のディレクトリを持つ。

import os

pid = os.getpid()  # 現在のプロセス ID

# コマンドライン引数
with open(f"/proc/{pid}/cmdline") as f:
    cmdline = f.read().replace("\0", " ")
    print(f"コマンド: {cmdline}")

# 環境変数
with open(f"/proc/{pid}/environ") as f:
    env = f.read().split("\0")
    for e in env[:3]:  # 最初の 3 つだけ
        print(e)

# ファイルディスクリプタ一覧
fd_dir = f"/proc/{pid}/fd"
for fd in os.listdir(fd_dir):
    link = os.readlink(f"{fd_dir}/{fd}")
    print(f"fd {fd} -> {link}")

/proc/self:自分自身への参照

/proc/self は常に現在のプロセスを指す特殊なシンボリックリンクだ。

import os

# PID を知らなくても自分の情報にアクセスできる
with open("/proc/self/status") as f:
    for line in f:
        if line.startswith(("Name:", "Pid:", "VmRSS:")):
            print(line.strip())
# Name:   python3
# Pid:    12345
# VmRSS:  28456 kB(実メモリ使用量)

/dev:デバイスへのアクセス

/dev はデバイスをファイルとして公開する。読み書きでデバイスを操作できる。

/dev/null

書き込んだデータを捨てる「ブラックホール」。読み込むと即座に EOF を返す。

/dev/zero

読み込むと無限にゼロバイトを返す。メモリの初期化やファイルの埋め草に使う。

/dev/urandom

読み込むと暗号学的に安全な乱数を返す。

/dev/tty

現在の端末デバイス。

import os

# /dev/urandom から乱数を読む
with open("/dev/urandom", "rb") as f:
    random_bytes = f.read(16)
    print(random_bytes.hex())
# 7a3b9c4d5e6f1a2b3c4d5e6f7a8b9c0d

# /dev/null に書き込む(捨てられる)
with open("/dev/null", "w") as f:
    f.write("この文字列は消える")

# /dev/zero から読む
with open("/dev/zero", "rb") as f:
    zeros = f.read(10)
    print(list(zeros))
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

システム情報の取得例

/proc を使うと、psutil などの外部ライブラリなしでシステム情報を取得できる。

def get_load_average():
    """ロードアベレージを取得"""
    with open("/proc/loadavg") as f:
        parts = f.read().split()
        return float(parts[0]), float(parts[1]), float(parts[2])

def get_uptime():
    """システム稼働時間を取得(秒)"""
    with open("/proc/uptime") as f:
        return float(f.read().split()[0])

def get_memory_usage():
    """メモリ使用状況を取得(KB)"""
    info = {}
    with open("/proc/meminfo") as f:
        for line in f:
            parts = line.split()
            key = parts[0].rstrip(":")
            value = int(parts[1])
            info[key] = value
    return info

print(f"Load: {get_load_average()}")
print(f"Uptime: {get_uptime() / 3600:.1f} hours")

mem = get_memory_usage()
used = mem["MemTotal"] - mem["MemAvailable"]
print(f"Memory: {used // 1024} MB / {mem['MemTotal'] // 1024} MB")

/proc への書き込み

一部の /proc ファイルは書き込み可能で、カーネルのパラメータを変更できる。

# IP フォワーディングを有効にする(要 root)
echo 1 > /proc/sys/net/ipv4/ip_forward

# ファイルディスクリプタの上限を確認
cat /proc/sys/fs/file-max
# Python から書き込む場合(要 root 権限)
def enable_ip_forward():
    with open("/proc/sys/net/ipv4/ip_forward", "w") as f:
        f.write("1")

注意点

移植性がない

/proc と /dev の構造は Linux 固有。macOS や Windows では使えない。移植性が必要なら psutil などのライブラリを使う。

フォーマットが変わる可能性

/proc の出力フォーマットはカーネルバージョンで変わることがある。本番コードではエラーハンドリングを忘れずに。

パーミッションに注意

他プロセスの情報や一部のシステム設定は root 権限が必要。

まとめ

/proc

カーネルとプロセスの情報を公開。読み取りでシステム状態を取得、書き込みでカーネルパラメータを変更

/dev

デバイスをファイルとして公開。null、zero、urandom などの特殊デバイスは便利ツールとして使える

これらの仮想ファイルシステムを理解すると、Linux システムの深い部分に Python からアクセスできるようになる。