On occasion I get output from a command that includes "key value" pairs, with possibly more than one pair per line. As a repeatable example, consider the command ip addr show dev eth0:

ip addr show dev eth0 | grep -v link/ether
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet brd scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe0f:dbb3/64 scope link
       valid_lft forever preferred_lft forever

For the purposes of this example I might want to capture the values following mtu, inet, and brd (i.e. 1500,, and respectively, here). It can be assumed that each keyword will not occur more than once in the input.

The only way I can see to handle this would be capture the output of the source command to a temporary variable, and repeatedly parse that until all the keywords have been processed.

Is there an easier or better way to pick out these "key value" pairs, discarding the remainder of the text?

Suggested example provision and unordered output:

ip addr show dev eth0 | someCommand brd inet mtu
mtu 1500
  • 1
    Just pipe the output to ... | tr \ \\n | sed -E '/^(mtu|inet|brd)$/!d;N;s/\n/ /' ; this assumes your keys and values are separated by a single space and keys/values cannot contain spaces. Jul 15 '15 at 12:34
  • @don_crissti that's an interesting approach (I tend to use sed for simple search/replace and avoid its loop and buffer options). Your example has given me opportunity to try out N too. Thank you!
    – roaima
    Jul 15 '15 at 13:52

Assuming that key name will appear at most once, here is how you may try.

ip addr show dev eth0 | perl -ne 'chomp; foreach $param (qw(mtu inet brd)) { /($param)\s+(\S+)/ && do { print "$1 $2\n"; }}'

Here's an awk solution which puts each word on its own line, and whenever it finds one of the specified keys, prints it and the following word. The keys are in fact a regular expression that needs to match the whole word.

ip addr show dev eth1 |
tr -s ' ' '\n' |
awk -v keys='mtu|inet|brd' '
    match($0, "^(" keys ")$") {printf "%s ", $0; getline; print}

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.