管道子流程标准输出到变量[重复]

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 &gt; /dev/null,如果你仍然看到输出,它将进入stderr。通过管道 stderr cmd 2&gt; /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 命令)

以上是关于管道子流程标准输出到变量[重复]的主要内容,如果未能解决你的问题,请参考以下文章

在 Bash 中同时捕获标准输出和标准错误 [重复]

如何将标准输出转换为字符串(Python)[重复]

渲染管道子流程

渲染管道子流程

将标准输出重定向到文件[重复]

标准输出 pymssql 到变量