将os.system的输出赋值给一个变量并防止其显示在屏幕上

433
我想把使用os.system运行的命令的输出分配给一个变量,并防止它被输出到屏幕上。但是,在下面的代码中,输出被发送到屏幕上,并且var的值为0,我猜这意味着命令是否成功运行。有没有办法将命令输出分配给变量,并同时阻止其显示在屏幕上?
var = os.system("cat /etc/services")
print var #Prints 0

8
不要使用os.system(也不要使用os.popen, 根据你所接受的答案): 使用subprocess.Popen,它更好得多! - Alex Martelli
1
@AlexMartelli,使用subprocess.Popen()无法使用复杂命令(例如管道),但是可以使用os.system。 - vak
2
@vak,当然你可以在subprocess.Popen中使用管道等操作--只需要加上shell=True即可! - Alex Martelli
3
没有说明原因,仅仅说某事“更好”是没有用的。 - user650261
@IgnacioFernández,os.open和os.popen需要与subprocess.Popen的shell=True完全相同的执行确定性,因此没有任何理由避免使用后者。 - Alex Martelli
显示剩余3条评论
8个回答

648

从我很久以前提出的这个问题中,你可能想要使用的是popen

os.popen('cat /etc/services').read()

来自Python 3.6文档

这是使用subprocess.Popen实现的;更强大的管理和与子进程通信的方式,请参阅该类的文档。


这是与 subprocess 相关的代码:

import subprocess

proc = subprocess.Popen(["cat", "/etc/services"], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print("program output:", out)

7
请注意,Walter 的 subprocess.check_output 解决方案更接近于 Python 风格的一行代码,似乎你正在寻找这种解决方案,只要你不关心 stderr - chbrown
13
为什么subprocess比os.popen更好? - Martin Thoma
6
几乎从不应使用shell=True。请参见https://docs.python.org/3/library/subprocess.html#security-considerations。 - dylnmc
65
每次遇到这个问题,我都在想:为什么要用三行复杂的代码代替一行明显的代码更好呢? - Ant6n
4
在这种情况下,几乎永远不应该使用 shell=True,而且这样做也是错误的。shell=True 会使 shell 成为子进程,而不是 cat,因此 outerrshell 进程的标准输出/错误,而不是 cat 进程的。 - villapx
显示剩余9条评论

235

你可能还想看看 subprocess 模块,它被设计用来替代整个 Python popen 系列调用。

import subprocess
output = subprocess.check_output("cat /etc/services", shell=True)
它的优点在于您可以非常灵活地调用命令,连接标准输入/输出/错误流等方式也很多。

3
请注意,check_output 是在 Python 2.7 中新增的功能。具体信息请参阅https://docs.python.org/2.7/library/subprocess.html#subprocess.check_output。 - phyatt
3
请将 stderr=subprocess.STDOUT 添加进去,以捕获标准错误信息并将其合并到标准输出流中。 - Dolan Antenucci
3
我使用了这个方法和 systeminfo 命令。输出结果非常丑陋,类似于这样 b'\r\nHost Name: DIMUTH-LAPTOP\r\nOS Name: Microsoft Windows 10 Pro\r\nOS Version: 10.0.10240 N/A Build 10240\r\nOS Manufacturer: Microsoft Corporation - ghost21blade
如何逐行打印输出?因为上面的输出很混乱。 - ghost21blade
4
@ghost21blade,你可能想要研究一下这个:output.decode("utf-8").split("\n") 或者你可以用任何你喜欢的方式处理它。但首先你必须将其转换为字符串 - TrainedMusician
显示剩余2条评论

48

commands模块是一个相对高级的方法来实现这个目的:

import commands
status, output = commands.getstatusoutput("cat /etc/services")

状态为0,输出是/etc/services的内容。


61
引用自commands模块的文档:“从2.6版本开始已过时:Python 3中已删除commands模块,应使用subprocess模块代替。” - Cristian Ciupitu
7
虽然它有些过时,但有时你只是想快速简单地用几行代码完成一些任务。 - fIwJlxSzApHEZIl
7
@advocate 请查看subprocess的check_output命令。它快速,易用,并且不会很快过时! - Luke Stanley

43

对于Python 3.5+,建议您使用subprocess模块中的run函数。它返回一个CompletedProcess对象,您可以轻松地获取输出以及返回代码。由于您只对输出感兴趣,因此可以编写以下实用程序包装器。

from subprocess import PIPE, run

def out(command):
    result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True)
    return result.stdout

my_output = out("echo hello world")
# Or
my_output = out(["echo", "hello world"])

不要忘记在run()中加入“capture_output=True”的选项。 - Elysiumplain
1
使用以下代码: result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True, capture_output=True)当注入capture_output时,会返回以下错误信息:ValueError: stdout和stderr参数不能与capture_output一起使用。 - Laice

35

我知道这个问题已经有答案了,但我想分享一种通过使用 from x import x 和函数来更好地调用 Popen 的方法:

我知道这个问题已经有答案了,但我想分享一种通过使用 from x import x 和函数来更好地调用 Popen 的方法:

from subprocess import PIPE, Popen


def cmdline(command):
    process = Popen(
        args=command,
        stdout=PIPE,
        shell=True
    )
    return process.communicate()[0]

print cmdline("cat /etc/services")
print cmdline('ls')
print cmdline('rpm -qa | grep "php"')
print cmdline('nslookup google.com')

2
三年后,这是对我有用的。我把它放在一个名为 cmd.py 的单独文件中,然后在我的主文件中写入 from cmd import cmdline 并根据需要使用它。 - Fares K. A.
1
我曾遇到过os.system返回0的相同问题,但是我尝试了这种方法,它非常好用!而且作为额外的奖励,它看起来很整洁 :) 谢谢! - Sophie Muspratt

6

我使用os.system临时文件来完成它:

import tempfile, os

def readcmd(cmd):
    ftmp = tempfile.NamedTemporaryFile(suffix='.out', prefix='tmp', delete=False)
    fpath = ftmp.name
    if os.name=="nt":
        fpath = fpath.replace("/","\\") # forwin
    ftmp.close()
    os.system(cmd + " > " + fpath)
    data = ""
    with open(fpath, 'r') as file:
        data = file.read()
        file.close()
    os.remove(fpath)
    return data

3

Python 2.6和3具体建议避免使用PIPE来处理标准输出和错误输出。

正确的方式是:

import subprocess

# must create a file object to store the output. Here we are getting
# the ssid we are connected to
outfile = open('/tmp/ssid', 'w');
status = subprocess.Popen(["iwgetid"], bufsize=0, stdout=outfile)
outfile.close()

# now operate on the file

-1
from os import system, remove
from uuid import uuid4

def bash_(shell_command: str) -> tuple:
    """

    :param shell_command: your shell command
    :return: ( 1 | 0, stdout)
    """

    logfile: str = '/tmp/%s' % uuid4().hex
    err: int = system('%s &> %s' % (shell_command, logfile))
    out: str = open(logfile, 'r').read()
    remove(logfile)
    return err, out

# Example: 
print(bash_('cat /usr/bin/vi | wc -l'))
>>> (0, '3296\n')```

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接