管子处理标准输出到变量

我想使用子进程模块在 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.Python 吐出了这句话:

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
229683 次浏览

To get the output of ls, use stdout=subprocess.PIPE.

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

The command cdrecord --help outputs to stderr, so you need to pipe that indstead. You should also break up the command into a list of tokens as I've done below, or the alternative is to pass the shell=True argument but this fires up a fully-blown shell which can be dangerous if you don't control the contents of the command string.

>>> 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 #.
...

If you have a command that outputs to both stdout and stderr and you want to merge them, you can do that by piping stderr to stdout and then catching stdout.

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

As mentioned by Chris Morgan, you should be using proc.communicate() instead of 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 #.
...

With a = subprocess.Popen("cdrecord --help",stdout = subprocess.PIPE) , you need to either use a list or use shell=True;

Either of these will work. The former is preferable.

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


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

Also, instead of using Popen.stdout.read/Popen.stderr.read, you should use .communicate() (refer to the subprocess documentation for why).

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

If you are using python 2.7 or later, the easiest way to do this is to use the subprocess.check_output() command. Here is an example:

output = subprocess.check_output('ls')

To also redirect stderr you can use the following:

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



In the case that you want to pass parameters to the command, you can either use a list or use invoke a shell and use a single string.

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