pelos
pelos

Reputation: 1876

Get output of system ping without printing to the console

I want to call ping from Python and get the output. I tried the following:

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

However, this prints to the console, which I don't want.

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

Is there a way to not print to the console and just get the result?

Upvotes: 10

Views: 41227

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1121834

If you only need to check if the ping was successful, look at the status code; ping returns 2 for a failed ping, 0 for a success.

I'd use subprocess.Popen() (and not subprocess.check_call() as that raises an exception when ping reports the host is down, complicating handling). Redirect stdout to a pipe so you can read it from 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'))

You can switch to subprocess.DEVNULL* if you want to ignore the output; use proc.wait() to wait for ping to exit; you can add -q to have ping do less work, as it'll produce less output with that switch:

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

In both cases, proc.returncode can tell you more about why the ping failed, depending on your ping implementation. See man ping for details. On OS X the manpage states:

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>.

and man sysexits lists further error codes.

The latter form (ignoring the output) can be simplified by using subprocess.call(), which combines the proc.wait() with a proc.returncode return:

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

* subprocess.DEVNULL is new in Python 3.3; use open(os.devnull, 'wb') in it's place in older Python versions, making use of the os.devnull value, e.g.:

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

Upvotes: 8

davidism
davidism

Reputation: 127190

To get the output of a command, use subprocess.check_output. It raises an error if the command fails, so surround it in a try block.

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

To use ping to know whether an address is responding, use its return value, which is 0 for success. subprocess.check_call will raise and error if the return value is not 0. To suppress output, redirect stdout and stderr. With Python 3 you can use subprocess.DEVNULL rather than opening the null file in a block.

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

In general, use subprocess calls, which, as the docs describe, are intended to replace os.system.

Upvotes: 16

Related Questions