Python:运行 os.system 后如何获取标准输出? [复制]

Posted

技术标签:

【中文标题】Python:运行 os.system 后如何获取标准输出? [复制]【英文标题】:Python: How to get stdout after running os.system? [duplicate] 【发布时间】:2013-09-15 08:42:07 【问题描述】:

我想在运行os.system 调用后在变量中获取stdout

我们以这一行为例:

batcmd="dir"
result = os.system(batcmd)

result 将包含错误代码(Windows 下的stderr 0 或某些Linux 下的1 以上示例)。

如何在执行的命令中不使用重定向来获取上述命令的stdout

【问题讨论】:

改用subprocess 模块。 os.system让您访问过程输入或输出。 @MartijnPieters 这是唯一的方法吗? 不,但是subprocess 封装了 Windows 和 POSIX 系统之间的差异,比你能实现的要好得多。为什么要重新发明***? 相信我,我曾经重新发明过那个***。来自 C 背景,跳好老式的 fork/exec/pipe 舞几乎是自然而然的事,但@MartijnPieters 是对的,只需使用 subprocess 就可以了。 Python 2.7 添加了subprocess.check_output() function,这足以满足您的需求,但除此之外,这两个目标几乎相同。 【参考方案1】:

如果您只需要stdout 输出,请查看subprocess.check_output()

import subprocess

batcmd="dir"
result = subprocess.check_output(batcmd, shell=True)

因为您使用的是os.system(),所以您必须设置shell=True 才能获得相同的行为。您确实需要注意 security concerns 关于将不受信任的参数传递给您的 shell。

如果您还需要捕获stderr,只需在调用中添加stderr=subprocess.STDOUT

result = subprocess.check_output([batcmd], stderr=subprocess.STDOUT)

将错误输出重定向到默认输出流。

如果知道输出是文本,则添加text=True,以平台默认编码解码返回的字节值;如果该编解码器对于您收到的数据不正确,请改用 encoding="..."

【讨论】:

在 Windows 中只有运行 cmd.exe result = subprocess.check_output(["cmd.exe", batcmd]) 才能工作 @EduardFlorinescu:或者使用shell=Truesubprocess 文档中提到了这一点,但我已在此处明确说明。 有没有办法在 Jupyter Notebook 中做到这一点?看起来它只返回一个空字符串。 @LouisYang:是的,这也适用于 Jupyter 笔记本。但考虑到 Python 子进程的当前工作目录可能不同,您可能需要将 cwd 参数设置为 subprocess.check_output()【参考方案2】:
import subprocess
string="echo Hello world"
result=subprocess.getoutput(string)
print("result::: ",result)

【讨论】:

您可能需要解释为什么这个答案是对当前高排名答案的改进。如果它是一个新的 api,或者某些东西已被弃用,这很重要,这样其他人才能区分优缺点。 应该提到的是,这确实使用了 Python 2 中命令模块的遗留遗留物,但是它没有在此处找到的 API 文档中标记为已弃用:docs.python.org/3/library/subprocess.html#subprocess.getoutput 这对我有很大帮助,因为我有一个相当老的进程,并且在成功调用时不返回 0,这意味着无法使用 check_output,并且 call() 没有按预期工作。点赞!【参考方案3】:

我不得不使用 os.system,因为子进程给我一个更大的任务的内存错误。此问题的参考here。因此,为了获得 os.system 命令的输出,我使用了以下解决方法:

import os

batcmd = 'dir'
result_code = os.system(batcmd + ' > output.txt')
if os.path.exists('output.txt'):
    fp = open('output.txt', "r")
    output = fp.read()
    fp.close()
    os.remove('output.txt')
    print(output)

【讨论】:

os.system() 在后台使用fork()/clone(),那么这有什么更好的呢? 我所知道的是一种方法有效,另一种无效。我正在使用 ubuntu 和这个命令: out = os.system('ffmpeg -i ' + convert_filename + ' -ss ' + str(thumbnail_frame_time) + ' -vf scale=254:152 -vframes 1 -vcodec png -an - y ' + 文件名 + '.png') 这很不安全。在将它们替换为 UNIX 命令之前,在所有文件名上使用 shlex.quote()(或其 python 2.x 等效的 pipes.quote()),或者将文件放入名为 $(rm -rf ~)'$(rm -rf ~)'.mpg 的上传文件夹中的人可能会导致您度过一个非常糟糕的一天. 你说得对,谢谢。【参考方案4】:

commands 也可以。

import commands
batcmd = "dir"
result = commands.getoutput(batcmd)
print result

它适用于 linux,python 2.7。

【讨论】:

请记住它是deprecated since Python 2.6。 已弃用 == 不会对库进行进一步的代码更改/修复 ...并且可能会在未来的版本中被删除。【参考方案5】:

这些答案对我不起作用。我必须使用以下内容:

import subprocess
p = subprocess.Popen(["pwd"], stdout=subprocess.PIPE)
out = p.stdout.read()
print out

或者作为一个函数(在 Python 2.6.7 上我需要使用 shell=True 并且 check_output 直到 2.7 才添加,使其无法在此处使用):

def system_call(command):
    p = subprocess.Popen([command], stdout=subprocess.PIPE, shell=True)
    return p.stdout.read()

【讨论】:

谢谢。可悲的是,我们中的一些人正在使用 2.6!【参考方案6】:

我想扩展 Windows 解决方案。在 Python 2.7.5 中使用 IDLE,当我从文件 Expts.py 运行此代码时:

import subprocess
r = subprocess.check_output('cmd.exe dir',shell=False) 
print r

...在Python Shell中,我只得到与“cmd.exe”对应的输出; “dir”部分被忽略。但是,当我添加 /K 或 /C 之类的开关时...

import subprocess
r = subprocess.check_output('cmd.exe /K dir',shell=False) 
print r

...然后在 Python Shell 中,我得到了我期望的所有内容,包括目录列表。哇哦!

现在,如果我在 DOS Python 命令窗口中尝试任何相同的操作,不使用开关或使用 /K 开关,它似乎会使窗口挂起,因为它正在运行子进程 cmd.exe 并等待进一步输入 - 输入 'exit' 然后点击 [enter] 释放。但是使用 /K 开关,它可以完美地工作并将您返回到 python 提示符。那么好吧。

更进一步...我认为这很酷...当我改为在 Expts.py 中执行此操作时:

import subprocess
r = subprocess.call("cmd.exe dir",shell=False) 
print r

...弹出一个新的 DOS 窗口并保持在那里,只显示“cmd.exe”的结果,而不是“dir”的结果。当我添加 /C 开关时,DOS 窗口打开和关闭非常快,然后我才能看到任何东西(正如预期的那样,因为 /C 在完成后终止)。当我改为添加 /K 开关时,DOS 窗口会弹出并保持打开状态,并且我会得到所有我期望的输出,包括目录列表。

如果我从 DOS Python 命令窗口尝试相同的操作(subprocess.call 而不是 subprocess.check_output);所有输出都在同一个窗口内,没有弹出窗口。没有开关,“dir”部分再次被忽略,提示符从 python 提示符变为 DOS 提示符(因为 cmd.exe 子进程在 python 中运行;再次键入“exit”,您将恢复到 python 提示符)。添加 /K 开关会打印出目录列表并将提示从 python 更改为 DOS,因为 /K 不会终止子进程。将开关更改为 /C 为我们提供了所有预期的输出并返回到 python 提示符,因为子进程根据 /C 终止。

对于冗长的回复感到抱歉,但我对这个董事会感到沮丧,因为许多简洁的“答案”充其量是行不通的(似乎是因为它们没有经过测试 - 就像 Eduard F 在我上面的回复一样,它缺少开关)或更糟糕的是,它们是如此简洁以至于它们根本没有多大帮助(例如,'尝试子进程而不是os.system'......是的,好的,现在是什么??)。相比之下,我提供了我测试过的解决方案,并展示了它们之间的细微差别。花了很多时间但是... 希望这会有所帮助。

【讨论】:

您的解决方案 (subprocess.call("cmd.exe dir",shell=False) ) 在 ubuntu 12.04 下工作,除了 shell=True。谢谢!

以上是关于Python:运行 os.system 后如何获取标准输出? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

python cmd命令调用

Python之os.popen和os.system

pythonos.system() & os.popen() 在 python 执行 cmd 指令

如何结束作为 os.system() 调用运行的线程(Python)

21 python调用外部系统命令

在新终端上运行 os.system 命令 - Python 3