python中有很多種方式是可以直接執行系統命令的,類似於os.system
、commands
(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的虛擬機器上通過此方法執行vgs
、vgs
等命令時,會輸出大量異常資訊
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
的原始碼,對其中的一次額引數有了簡單的認識。
果然還是要多看原始碼。