【问题标题】:Get output of system ping without printing to the console获取系统 ping 的输出而不打印到控制台
【发布时间】:2015-02-27 15:50:00
【问题描述】:

我想从 Python 调用 ping 并获取输出。我尝试了以下方法:

response = os.system("ping "+ "- c")

但是,这会打印到控制台,这是我不想要的。

PING 10.10.0.100 (10.10.0.100) 56(86) bytes of data.
64 bytes from 10.10.0.100: icmp_seq=1 ttl=63 time=0.713 ms
64 bytes from 10.10.0.100: icmp_seq=2 ttl=63 time=1.15 ms

有没有办法不打印到控制台而只得到结果?

【问题讨论】:

  • 得到什么结果? ping stdout 输出还是进程的状态码?
  • 我只是想知道机器是否启动。
  • @user1704282 如果机器启动了,但没有响应 ping 怎么办?

标签: python


【解决方案1】:

如果只需要检查ping是否成功,查看状态码; ping 返回 2 表示 ping 失败,0 表示成功。

我会使用subprocess.Popen()(并且 subprocess.check_call() 因为当ping 报告主机已关闭时会引发异常,从而使处理复杂化)。将 stdout 重定向到管道,以便您可以从 Python 中读取它:

ipaddress = '198.252.206.140'  # guess who
proc = subprocess.Popen(
    ['ping', '-c', '3', ipaddress],
    stdout=subprocess.PIPE)
stdout, stderr = proc.communicate()
if proc.returncode == 0:
    print('{} is UP'.format(ipaddress))
    print('ping output:')
    print(stdout.decode('ASCII'))

如果要忽略输出,可以切换到subprocess.DEVNULL*;使用proc.wait() 等待ping 退出;您可以添加 -q 以使 ping 做更少的工作,因为使用该开关会产生更少的输出:

proc = subprocess.Popen(
    ['ping', '-q', '-c', '3', ipaddress],
    stdout=subprocess.DEVNULL)
proc.wait()
if proc.returncode == 0:
    print('{} is UP'.format(ipaddress))

在这两种情况下,proc.returncode 可以告诉您更多关于 ping 失败的原因,具体取决于您的 ping 实施。有关详细信息,请参阅man ping。在 OS X 上,联机帮助页指出:

EXIT STATUS
     The ping utility exits with one of the following values:

     0       At least one response was heard from the specified host.

     2       The transmission was successful but no responses were received.

     any other value
             An error occurred.  These values are defined in <sysexits.h>.

man sysexits 列出更多错误代码。

后一种形式(忽略输出)可以通过使用subprocess.call() 来简化,它将proc.wait()proc.returncode 返回:

status = subprocess.call(
    ['ping', '-q', '-c', '3', ipaddress],
    stdout=subprocess.DEVNULL)
if status == 0:
    print('{} is UP'.format(ipaddress))

*subprocess.DEVNULL 在 Python 3.3 中是新的;在旧 Python 版本中使用open(os.devnull, 'wb'),利用os.devnull value,例如:

status = subprocess.call(
    ['ping', '-q', '-c', '3', ipaddress],
    stdout=open(os.devnull, 'wb'))

【讨论】:

  • 我们如何为这个测试添加一个“时间限制”?例如,如果 ping 请求“挂起”=> 那么有几种情况你可以永远等待。我们可以将测试限制为(例如)10 秒,然后检查输出吗?
  • @Kosem:subprocess 模块支持超时。在上面的示例中,您可以使用proc.wait(timeout=&lt;seconds&gt;),或将相同的参数传递给subprocess.call() 示例。
  • @sorh 没有版本信息和错误我无法帮助您完成工作。我已经重新测试了我在 Python 3.8 上的答案中的所有示例,它们仍然对我有用。
  • 最终我设法运行它,'-c' 开关由于某种原因无法正常工作,但这对我也不利,因为 cmd 窗口每次运行时都会短暂弹出。 .
  • @sorh:-c 是“计数”选项。如果您使用的是 Windows,请查看 ping 命令的文档并查看支持哪些命令行选项。 This documentation 建议您需要使用/n(或-n)而不是-c,并且没有出现-q 的等效开关。但是,这似乎只适用于 Windows Server。
【解决方案2】:

要获取命令的输出,请使用subprocess.check_output。如果命令失败,则会引发错误,因此请将其括在 try 块中。

import subprocess

try:
    response = subprocess.check_output(
        ['ping', '-c', '3', '10.10.0.100'],
        stderr=subprocess.STDOUT,  # get all output
        universal_newlines=True  # return string not bytes
    )
except subprocess.CalledProcessError:
    response = None

要使用ping 来了解地址是否在响应,请使用其返回值,即成功为0。如果返回值不为 0,subprocess.check_call 将引发并出错。要抑制输出,请重定向 stdoutstderr。在 Python 3 中,您可以使用 subprocess.DEVNULL 而不是在一个块中打开空文件。

import os
import subprocess

with open(os.devnull, 'w') as DEVNULL:
    try:
        subprocess.check_call(
            ['ping', '-c', '3', '10.10.0.100'],
            stdout=DEVNULL,  # suppress output
            stderr=DEVNULL
        )
        is_up = True
    except subprocess.CalledProcessError:
        is_up = False

一般来说,使用 subprocess 调用,正如文档所述,它旨在替换 os.system

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-31
    • 1970-01-01
    • 2014-09-06
    • 1970-01-01
    • 2022-11-24
    • 2021-12-13
    相关资源
    最近更新 更多