2010-12-22 31 views
64

我想使用子流程模块在pythong中运行命令,并将输出存储在变量中。但是,我不希望将命令的输出打印到终端。 对于此代码:将子流程标准输出转换为变量

def storels(): 
    a = subprocess.Popen("ls",shell=True) 
storels() 

我得到的终端目录列表,而不是有它存储在a。我也试过:

def storels(): 
     subprocess.Popen("ls > tmp",shell=True) 
     a = open("./tmp") 
     [Rest of Code] 
storels() 

这也打印ls的输出到我的终端。我甚至用有点过时的os.system方法试过这个命令,因为在终端中运行ls > tmp并不打印ls到终端,而是将它存储在tmp中。然而,同样的事情发生。

编辑:

我得到以下marcog的意见后,下面的错误,但运行更复杂的命令,只有当。 cdrecord --help。蟒蛇吐出了这一点:

Traceback (most recent call last): 
    File "./install.py", line 52, in <module> 
    burntrack2("hi") 
    File "./install.py", line 46, in burntrack2 
    a = subprocess.Popen("cdrecord --help",stdout = subprocess.PIPE) 
    File "/usr/lib/python2.6/subprocess.py", line 633, in __init__ 
    errread, errwrite) 
    File "/usr/lib/python2.6/subprocess.py", line 1139, in _execute_child 
    raise child_exception 
OSError: [Errno 2] No such file or directory 
+2

请注意,Python文档中不鼓励使用`shell = true`。 http://docs.python.org/2/library/subprocess.html#frequently-used-arguments – SamHuckaby 2013-12-09 16:13:51

回答

101

要获得ls输出,使用stdout=subprocess.PIPE

>>> proc = subprocess.Popen('ls', stdout=subprocess.PIPE) 
>>> output = proc.stdout.read() 
>>> print output 
bar 
baz 
foo 

命令cdrecord --help输出到标准错误,所以你需要的是indstead管。你也应该把命令分解成一个令牌列表,就像我在下面所做的那样,或者另一种方法是通过shell=True的参数,但是这会激发一个完整的shell,如果你不控制命令字符串。

>>> proc = subprocess.Popen(['cdrecord', '--help'], stderr=subprocess.PIPE) 
>>> output = proc.stderr.read() 
>>> print output 
Usage: wodim [options] track1...trackn 
Options: 
    -version print version information and exit 
    dev=target SCSI target to use as CD/DVD-Recorder 
    gracetime=# set the grace time before starting to write to #. 
... 

如果您有输出到标准输出和标准错误的命令,你想合并它们,你可以做到这一点通过管道错误输出到标准输出,然后抓住标准输出。

subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 

正如Chris Morgan提到的,你应该用proc.communicate()代替proc.read()

>>> proc = subprocess.Popen(['cdrecord', '--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
>>> out, err = proc.communicate() 
>>> print 'stdout:', out 
stdout: 
>>> print 'stderr:', err 
stderr:Usage: wodim [options] track1...trackn 
Options: 
    -version print version information and exit 
    dev=target SCSI target to use as CD/DVD-Recorder 
    gracetime=# set the grace time before starting to write to #. 
... 
+0

好吧,这适用于'ls',但后来我遇到了一个不同的问题,当试图运行一个不同的命令。当我尝试使用该方法运行“cdrecord --help”时,出现跟踪错误。 – Insomaniacal 2010-12-23 00:04:47

+0

@Insomaniacal查看编辑 – marcog 2010-12-23 00:12:52

8

随着a = subprocess.Popen("cdrecord --help",stdout = subprocess.PIPE) ,你需要或者使用列表,或使用shell=True;

其中任何一个都可以。前者是可取的。

a = subprocess.Popen(['cdrecord', '--help'], stdout=subprocess.PIPE) 

a = subprocess.Popen('cdrecord --help', shell=True, stdout=subprocess.PIPE) 

而且,而是采用Popen.stdout.read/Popen.stderr.read,你应该使用.communicate()(参见子文档为什么)。

proc = subprocess.Popen(['cdrecord', '--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
stdout, stderr = proc.communicate() 
22

如果您使用python 2.7或更高版本,最简单的方法是使用subprocess.check_output()命令。这里有一个例子:

output = subprocess.check_output('ls') 

要同时重定向标准错误,你可以使用以下命令:

output = subprocess.check_output('ls', stderr=subprocess.STDOUT) 



在要参数传递给该命令的情况下,你可以使用一个列表或使用调用一个shell并使用一个字符串。

output = subprocess.check_output(['ls', '-a']) 
output = subprocess.check_output('ls -a', shell=True)