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
是是正常的
[[email protected] 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
[[email protected] test]# echo $?
0
复制代码
命令输出没有问题,执行返回码也是一致的正常,为什么在python执行的时候会有这些异常输出呢?
再次感谢强大的(Google)[www.google.com],在*中的找到了相似问题。 其中第二个回答是想要的结果。
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
的源码,对其中的一次额参数有了简单的认识。
果然还是要多看源码。