Parse output of 'ip addr' via Python
Question: I need some help parsing the output of the `ip addr` command as dumped to a
text file, with contents like this:

    
    
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN \    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    1: lo    inet 127.0.0.1/8 scope host lo
    1: lo    inet6 ::1/128 scope host \       valid_lft forever preferred_lft forever
    2: em1: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP qlen 1000\    link/ether b8:ca:3a:65:43:3c brd ff:ff:ff:ff:ff:ff
    3: em2: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP qlen 1000\    link/ether b8:ca:3a:65:43:3c brd ff:ff:ff:ff:ff:ff
    4: em3: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond1 state UP qlen 1000\    link/ether b8:ca:3a:65:43:3e brd ff:ff:ff:ff:ff:ff
    5: em4: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond1 state UP qlen 1000\    link/ether b8:ca:3a:65:43:3e brd ff:ff:ff:ff:ff:ff
    6: p1p1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000\    link/ether a0:36:9f:27:13:48 brd ff:ff:ff:ff:ff:ff
    7: p1p2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000\    link/ether a0:36:9f:27:13:49 brd ff:ff:ff:ff:ff:ff
    8: p1p3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000\    link/ether a0:36:9f:27:13:4a brd ff:ff:ff:ff:ff:ff
    9: p1p4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000\    link/ether a0:36:9f:27:13:4b brd ff:ff:ff:ff:ff:ff
    10: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP \    link/ether b8:ca:3a:65:43:3c brd ff:ff:ff:ff:ff:ff
    10: bond0    inet6 fe80::baca:3aff:fe65:433c/64 scope link \       valid_lft forever preferred_lft forever
    12: bond1: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP \    link/ether b8:ca:3a:65:43:3e brd ff:ff:ff:ff:ff:ff
    12: bond1    inet6 fe80::baca:3aff:fe65:433e/64 scope link \       valid_lft forever preferred_lft forever
    

As you can see, there will be lines that start similarly (^\d: $device), and
I'm at a loss of how to be able to iterate over the file, and pull out select
information (ipv4 addr, ipv6 addr if present, link state, hw addr) for each
device when this information is spread over multiple lines.

Suggestions?


Answer: 
    from itertools import groupby
    
    interfaces = {}
    with open('ip.txt') as f:
        lines = [line for line in f if line.strip()]
        # group by line number
        for key, group in groupby(lines, lambda x: x.split()[0]):
            interface = []
            for thing in group:
                # append lines without repeating part
                interface += thing.split()[2:]
            if interface:
                interfaces[key] = interface
    
        for key, interface in interfaces.items():
            for x in ['inet', 'inet6', 'state', 'link/ether']:
                if x in interface:
                    idx = interface.index(x)
                    print '%s %s=%s' % (key, x, interface[idx+1])
    
    
    $ python ip.py
    3: state=UP
    3: link/ether=b8:ca:3a:65:43:3c
    4: state=UP
    4: link/ether=b8:ca:3a:65:43:3e
    5: state=UP
    5: link/ether=b8:ca:3a:65:43:3e
    1: inet=127.0.0.1/8
    1: inet6=::1/128
    1: state=UNKNOWN
    10: inet6=fe80::baca:3aff:fe65:433c/64
    10: state=UP
    10: link/ether=b8:ca:3a:65:43:3c
    2: state=UP
    2: link/ether=b8:ca:3a:65:43:3c
    8: state=DOWN
    8: link/ether=a0:36:9f:27:13:4a
    9: state=DOWN
    9: link/ether=a0:36:9f:27:13:4b
    12: inet6=fe80::baca:3aff:fe65:433e/64
    12: state=UP
    12: link/ether=b8:ca:3a:65:43:3e
    6: state=DOWN
    6: link/ether=a0:36:9f:27:13:48
    7: state=DOWN
    7: link/ether=a0:36:9f:27:13:49
    

