Python關於使用subprocess.Popen時遇到的一個小問題記錄

我就看看發表於2018-03-31

python中有很多種方式是可以直接執行系統命令的,類似於os.systemcommands(python3中已經移除)、subprocess等。

其中os.system的返回值只是執行命令的返回狀態碼,並不會得到命令的執行輸出;commands在Windows平臺下並不好使;日常中更多的還是使用subprocess

之前只是常規的使用subprocess簡單的封裝一個方法使用,如下:

# utf-8
"""
python 2.7的執行環境
"""
from subprocess import Popen, PIPE


def getoutput(cmd, cwd=None, env=None):
    p = Popen(cmd, stdout=PIPE, stdin=PIPE, 
              stderr=PIPE, cwd=cwd, env=env, 
              shell=True)
    out, err = p.communicate()
    if err:
        print err
    return p.returncode, out

status, output = getoutput('whoami')
複製程式碼

多數情況下這個方法執行都是正常的,之前前幾天,遇到一個問題。

在Redhat 6.8的虛擬機器上通過此方法執行vgsvgs等命令時,會輸出大量異常資訊

File descriptor 4 (pipe:[526520]) leaked on pvremove invocation. Parent PID 46499:python
File descriptor 5 (pipe:[526520]) leaked on pvremove invocation. Parent PID 46499:python
File descriptor 6 (pipe:[526520]) leaked on pvremove invocation. Parent PID 46499:python
...
複製程式碼

實際在虛擬機器中命令列直接執行lvs是是正常的

[root@localhost test]# lvs
LV          VG        Attr        LSize        Pool        Origin       Data%       Meta%        Move        log         Cpy%Sync  Convert
lvoradata   appvg    -wi-ao----   270.00g
lvu01       appvg    -wi-ao----   30.00g
root        vg00     -wi-ao----   19.53g
[root@localhost test]# echo $?
0
複製程式碼

命令輸出沒有問題,執行返回碼也是一致的正常,為什麼在python執行的時候會有這些異常輸出呢?

再次感謝強大的(Google)[www.google.com],在Stackoverflow中的找到了相似問題。 其中第二個回答是想要的結果。

So for lvm commands like pvremove, you can avoid the leak by setting close_fds=True in your subprocess.Popen call.

原來,在系統呼叫時,lvm必須要標準描述符的stdin stdout stderr才可用,如果是其他的就會被關閉並且丟擲如上的提示資訊。所以,通過指定close_fds=True繼承檔案描述符,從而解決這個問題。

from subprocess import Popen, PIPE


def getoutput(cmd, cwd=None, env=None):
    p = Popen(cmd, stdout=PIPE, stdin=PIPE, 
              stderr=PIPE, cwd=cwd, env=env, 
              shell=True, close_fds=True)
    out, err = p.communicate()
    if err:
        print err
    return p.returncode, out
複製程式碼

在使用subprocess.Popen類時,實際對內部引數並不瞭解,只知道要這麼做,但並不清楚為什麼要這麼做。在解決以上問題的過程中,才算是看了次subprocess的原始碼,對其中的一次額引數有了簡單的認識。

果然還是要多看原始碼。

參考

Leak when run subprocess in python

Python subprocess

相關文章