Skip to content Skip to sidebar Skip to footer

Python Subprocess Output Without \n

Here is a simple script running subprocess that retrieves IP from the ifconfig command output from the terminal. I have noticed that subprocess.check_output() always returns a valu

Solution 1:

For a generic way :

subprocess.check_output("echo hello world", shell=True).strip()

Solution 2:

subprocess.check_output() does not add a newline. echo does. You can use the -n switch to suppress the newline, but you have to avoid using the shell built-in implementation (so use /bin/echo):

>>>import subprocess>>>subprocess.check_output('/bin/echo -n hello world', shell=True)
'hello world'

If you use echo -n instead, you could get the string '-n hello world\n', as not all sh implementations support the -n switch support echo (OS X for example).

You could always use str.rstrip() or str.strip() to remove whitespace, of course, but don't blame subprocess here:

>>> subprocess.check_output('echo hello world', shell=True).rstrip('\n')
'hello world'

Your question update added a more complex example using awk and grep:

subprocess.check_output("ifconfig en0 | awk '{ print $2}' | grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}'", shell=True)

Here grep adds the (final) newline. grep -o may print just the matching text, but still adds a newline to separate matches. See the grep manual:

-o --only-matching

Print only the matched (non-empty) parts of matching lines, with each such part on a separate output line.

Emphasis mine.

You can add a tr -d '\n' at the end to remove any newlines from the output of your pipe:

>>>subprocess.check_output(..."ifconfig en0 | awk '{ print $2}' | "..."grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}' | "..."tr -d '\n'", shell=True)
'172.17.174.160'

Solution 3:

You can str.rstrip any newline or use what Martijn suggests, you can also parse the output using python with the need to awk or grep which won't add any newlines:

You can split:

out = subprocess.check_output(["ifconfig", "en0"])

for line in out.splitlines():
    if line.lstrip().startswith("inet "):
        print(line.split()[1].split(":", 2)[1])
        print(ip.search(line))
        break

Or use your own regex:

import  re

out = subprocess.check_output(["ifconfig", "en0"])

print(re.search('([0-9]{1,3}[\.]){3}[0-9]{1,3}', out).group())

The point being you don't need awk or grep.

If you want to match ipv4 or ipv6 and also catch when there is an error returned i.e no such interface you can catch a CalledProcessError which will be raised for any non zero exit status, it is easy use the regex for ipv4 but for ipv6 it is simpler to use inet6 to grab the ipv6 address.

from subprocess import check_output, CalledProcessError
import re

defget_ip(iface, ipv="ipv4"):
    try:
       out = check_output(["ifconfig", iface])
    except CalledProcessError as e:
        print(e.message)
        returnFalsetry:
        if ipv == "ipv4":
            return re.search('([0-9]{1,3}[\.]){3}[0-9]{1,3}', out).group()
        return re.search("(?<=inet6 addr:)(.*?)(?=/)", out).group().lstrip()
    except AttributeError as e:
        print("No {} address for interface {}".format(ipv, iface))
        returnFalse

Demo:

In [2]: get_ip("wlan0")
Out[2]: '192.168.43.168'

In [3]: get_ip("wlan0","ipv6")
Out[3]: 'fe80::120b:a9ff:fe03:bb10'

In [4]: get_ip("wlan1","ipv6")
wlan1: error fetching interface information: Device not found   
Out[4]: False

Solution 4:

This is what you have :

$ python
>>>import subprocess>>>subprocess.check_output("ifconfig eth0 | awk '{ print $2}' | grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}'", shell=True)
'172.31.94.116\n'

Try this instead :

$ python
>>>import subprocess>>>subprocess.check_output("ifconfig eth0 | awk '{ print $2}' | grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}'", shell=True).strip()
'172.31.94.116'

Post a Comment for "Python Subprocess Output Without \n"