管道子流程标准输出到变量[重复]
Posted
技术标签:
【中文标题】管道子流程标准输出到变量[重复]【英文标题】:Pipe subprocess standard output to a variable [duplicate] 【发布时间】:2011-05-29 17:20:38 【问题描述】:我想使用 subprocess 模块在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
【问题讨论】:
请注意,在 Python 文档中不鼓励使用shell=true
。 docs.python.org/2/library/…
【参考方案1】:
要获得ls
的输出,请使用stdout=subprocess.PIPE
。
>>> proc = subprocess.Popen('ls', stdout=subprocess.PIPE)
>>> output = proc.stdout.read()
>>> print output
bar
baz
foo
命令cdrecord --help
输出到stderr,所以你需要用管道代替。您还应该将命令分解为令牌列表,就像我在下面所做的那样,或者替代方法是传递 shell=True
参数,但这会启动一个成熟的外壳,如果您不控制它可能会很危险命令字符串的内容。
>>> 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 #.
...
如果您有一个同时输出到 stdout 和 stderr 的命令并且想要合并它们,您可以通过将 stderr 管道传输到 stdout 然后捕获 stdout 来实现。
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 #.
...
【讨论】:
好吧,这适用于“ls”,但后来我在尝试运行不同的命令时遇到了不同的问题。当我尝试使用该方法运行“cdrecord --help”时,出现回溯错误。 非常感谢!!做到了。如果你不介意我问,你会如何区分使用 stdout 方法和这个 stderr 方法? @Insomaniacal 在这种情况下,我知道使用通常被转储到 stderr。但一般来说,一个简单的测试是cmd > /dev/null
,如果你仍然看到输出,它将进入stderr。通过管道 stderr cmd 2> /dev/null
进行确认,它应该消失在 /dev/null
中。
@Insomaniacal:一般会使用stdout
,但有时会使用stderr
;一般来说,使用stdout
,除非它不起作用,然后尝试stderr
。我相信它可以安排在一些终端中以不同的方式为 stderr 着色,这样你就可以清楚地分辨出来。
在 Python3 下,output
不会是字符串,而是字节序列。尝试output.decode(encoding='utf-8')
或output.decode(encoding='latin-1')
获取字符串。【参考方案2】:
使用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)
此外,您应该使用.communicate()
,而不是使用Popen.stdout.read
/Popen.stderr.read
(请参阅子流程文档了解原因)。
proc = subprocess.Popen(['cdrecord', '--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
【讨论】:
【参考方案3】:如果您使用的是 python 2.7 或更高版本,最简单的方法是使用subprocess.check_output()
命令。这是一个例子:
output = subprocess.check_output('ls')
要同时重定向 stderr,您可以使用以下命令:
output = subprocess.check_output('ls', stderr=subprocess.STDOUT)
如果您想将参数传递给命令,您可以使用列表或调用 shell 并使用单个字符串。
output = subprocess.check_output(['ls', '-a'])
output = subprocess.check_output('ls -a', shell=True)
【讨论】:
这不会按要求抑制输出(“我不希望将命令的输出打印到终端”)。 这确实为我抑制了到终端的所有输出(只要我使用 stderr=subprocess.STDOUT 来捕获 STDOUT 和 STDERR)。你有一个不起作用的示例命令吗? Emre,我在 python 2.6 中看到过这种行为 这也不会抑制我的输出(使用 Python 3.9 并运行 OpenSSL 命令)以上是关于管道子流程标准输出到变量[重复]的主要内容,如果未能解决你的问题,请参考以下文章