7

I would like to print specific information about network configuration for different interfaces over all the servers I manage:

  • the interface name
  • the interface ipv4 address
  • the interface hardware mac address

Unfortunately, a simple ip -o addr show doesn't allow to parse easily its output with awk because of the line-breaks.

Is it possible to have ip addr show printed on exactly one line per interface?

Else, is it possible to achieve the same result using awk and/or sed? This goes beyond my knowledge of those two commands since the lines have to be concatenated tree by tree…

6 Answers 6

21

Just use --brief flag.

ip --brief address show
0
6

Newer versions of ip are able to output JSON formatted data with the -j option, which you can then process with a filter such as jq. For example this will print the IPv4 address on the eth0 interface:

$ ip -j addr show dev eth0 | jq -r '.[0].addr_info | map(select(.family == "inet"))[0].local'
192.168.0.1

Or to get a list of all IPv4 addresses on the machine, one per line:

ip -j addr show | jq -r 'map(.addr_info) | map(map(select(.family == "inet").local)) | flatten | .[]'
127.0.0.1
192.168.0.1
172.19.0.1
172.17.0.1
172.18.0.1

Remove select(...) to include IPv6 addresses for example. Many other variations are possible.

3

There's ip -o addr show, but it prints less information.

Here's a way to massage the output of ip addr show into one line per interface. Print a newline before the start of each interface, except at the first line; then print the line content; print a newline at the end of the file.

ip addr show |
awk '/^[^ ]/ && NR!=1 {print ""}
     {printf "%s", $0}
     END {print ""}'
0
sed  -nE  '/^[0-9]/! {H;$!d}     # accumulate trailing lines
           x                     # swap new leading line for accumulated gaggle
           s/[^ ]* ([^ ]*).* link\/[^ ]* ([^ ]*).* inet ([^ ]*).*/\1\t\3\t\2/p'

and the subst is pretty straightforward, identify and prettyprint 2nd word, word after link/anything, word after inet

2
  • here, you base yourself on the fact that "link" appears on the last line, don't you? what if it doesn't?
    – Jav
    Jul 15, 2015 at 9:09
  • 1
    Try it, play around with the substitution to see what it's getting and how it breaks things down. You could try /eth0/p for instance to show the eth0 block.`
    – jthill
    Jul 18, 2015 at 23:40
0

This gawk script will parse ip addr show to give you the information you requested. Multiple IPv4 addresses are concatenated with a comma

ip a | awk 'function outline() {if (link>"") {printf "%s %s %s\n", iface, inets, link}} $0 ~ /^[1-9]/ {outline(); iface=substr($2, 1, index($2,":")-1); inets=""; link=""} $1 == "link/ether" {link=$2} $1 == "inet" {inet=substr($2, 1, index($2,"/")-1); if (inets>"") inets=inets ","; inets=inets inet} END {outline()}'

Splitting this out so it's somewhat more readable,

ip addr show |
    awk '
        # Output function to format results (if any)
        function outline() {
            if (link>"") {printf "%s %s %s\n", iface, inets, link}
        }

        # Interface section starts here
        $0 ~ /^[1-9]/ {
            outline();                              # Output anything we previously collected
            iface=substr($2, 1, index($2,":")-1);   # Capture the interface name
            inets="";                               # Reset the list of addresses
            link=""                                 # and MAC too
        }

        # Capture the MAC
        $1 == "link/ether" {
            link=$2                   
        }

        # Capture an IPv4 address. Concatenate to previous with comma
        $1 == "inet" {
            inet=substr($2, 1, index($2,"/")-1);    # Discard /nn subnet mask
            if (inets>"") inets=inets ",";          # Suffix existing list with comma
            inets=inets inet                        # Append this IPv4
        }

        # Input processing has finished
        END {
            outline()                               # Output remaining collection
        }
    '

Example output

eth0 10.0.2.15 08:00:27:0f:db:b3
eth1 192.168.56.101 08:00:27:33:04:26
0

on debian:

man ip
...
       -o, -oneline
              output each record on a single line, replacing line feeds with the '\' character. This is convenient when you want to count records with wc(1) or to grep(1) the output.

EDITED@2021.01.06 as i misread the question earlier.

Try this:

ip addr show|xargs|sed 's/ \([0-9]*: \)/\n\1/g'

Each entry for adapter start with [0-9]*: which could be as a separator for you:

root@jprst0202:~# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: ip_vti0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
    link/none
    inet 10.7.11.1/24 brd 10.7.11.255 scope global tun0
       valid_lft forever preferred_lft forever
4: tun1: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
    link/none
    inet 10.7.5.1/24 brd 10.7.5.255 scope global tun1
       valid_lft forever preferred_lft forever
...

So:

  • xargs - put everything to single line
  • sed... - adds new line before each space,number(or multiple), colon and again space pattern

Result:

root@jprst0202:~# ip addr show|xargs|sed 's/ \([0-9]*: \)/\n\1/g'
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever
2: ip_vti0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0
3: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100 link/none inet 10.7.11.1/24 brd 10.7.11.255 scope global tun0 valid_lft forever preferred_lft forever
4: tun1: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100 link/none inet 10.7.5.1/24 brd 10.7.5.255 scope global tun1 valid_lft forever preferred_lft forever
5: tun2: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100 link/none inet 10.7.7.1/24 brd 10.7.7.255 scope global tun2 valid_lft forever preferred_lft forever
...
1
  • 2
    From the question, "Unfortunately, a simple ip -o addr show doesn't allow to parse easily its output with awk because of the line-breaks."
    – Jeff Schaller
    Nov 18, 2020 at 13:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.