os.pipe を使って subprocess.Popen する時の注意

ファイルディスクリプタは subprocess.Popen (というか fork)時にコピーされます。
なので、親プロセスと子プロセスの両方で、必要のないディスクリプタを閉じる必要があります。


しかしこれ、子プロセスが既存のコマンド(例えば tail)だったらファイルディスクリプタ閉じるのって無理じゃね?とか思ったのですが、fork して exec するまでの間に呼んでくれる、preexec_fn 関数というのを指定できるようなので、それを使います。

import os
from subprocess import Popen

r,w = os.pipe()
p = Popen(["tail", "-f", "hoge"], stdout=w,
          preexec_fn = lambda: os.close(r)) # 子プロセスの読み込み側を閉じる
os.close(w) # 親プロセスの書き込み側を閉じる

# あとは好きなだけ読む
rfd = os.fdopen(r)
for line in rfd:
  print line[:-1]

ただ、このコードだと、例外が起こった時にファイルディスクリプタ漏れる気がするので、もうちょいマジメにコード書かないといけないですね。