1

I've been trying to just return the inet values from UP adapters in ip addr,

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    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
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp0s7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:19:21:f5:04:42 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.100/24 brd 192.168.1.255 scope global enp0s7
       valid_lft forever preferred_lft forever
    inet6 fe80::4672:94c8:d31b:a04a/64 scope link
       valid_lft forever preferred_lft forever
3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
    link/ether 52:54:00:29:38:4d brd ff:ff:ff:ff:ff:ff

I have this regex to find that, but it returns the whole line, as is expected with grep:

([0-9]+:.{1,}state UP.{1,}(\n.{1,}?){1,}inet )\K([0-9]{1,3}\.?){4}

returns this:

inet 192.168.1.100/24 brd 192.168.1.255 scope global enp0s7

What I want it to do is just return 192.168.1.100 (the IP after inet). Can grep do this somehow, and if not, what is the correct way of going about this?

EDIT: OK, here's the relevant part of the script:

NUMOFNETWORKADAPTERS="$(ip addr | grep -Pc '[0-9]{1}: ')"
IPOFACTIVEADAPTER="$(ip addr | grep -Pc '(?<=state UP(.+\n){2,$NUMOFNETWORKADAPTER}?    inet )[^/]{1,15}')"

echo "LOCAL IP: $IPOFACTIVEADAPTER"

But this gives a lookbehind assertion is not fixed length error.

5
  • So did you (want to) use grep or perl or what? Probably not bash? Also, I think you could use .+ instead of .{1,}.
    – ilkkachu
    Commented Jul 24, 2016 at 15:18
  • How are you using this regex? Commented Jul 24, 2016 at 15:23
  • To answer both questions, I'm using this in a bash script, in which I was hoping to be able to use Perl regex. Commented Jul 24, 2016 at 15:40
  • I wondered how you made grep match a pattern spanning over more than one line. But the regexp in your code snippet isn't the same as the first one. The second one doesn't even work (on Debian Jessie, GNU grep 2.20), since the lookbehind assertion is not fixed length. I don't think that variable is expanded either, since it's in single quotes.
    – ilkkachu
    Commented Jul 24, 2016 at 17:22
  • pcregrep -o 'inet \K[\d.]+' Commented Jul 24, 2016 at 18:13

2 Answers 2

2

grep may not be the best option here, though with a PCRE enabled grep and -o one can grab the IP addresses with a zero-width lookbehind match to find inet and then match the IP following that.

ip addr | grep -Po '(?<=inet )[^/]+'

For the multi-line problem of "get inet addr of devices that are up", something like

ip link | awk -F: '/state UP/{print $2}' \
| while read updev; do \
  ip addr show $updev | grep -Po '(?<=inet )[^/]+'; done

may be more suitable.

3
  • OK, I've changed the script a bit, with your info, and I added it to my OP, but now it's giving the error: grep: lookbehind assertion is not fixed length Commented Jul 24, 2016 at 16:01
  • And you also said that grep may not be the best option for outputting this... what would be a better choice? Commented Jul 24, 2016 at 16:04
  • Thank you! That's what I was looking for. I'm somewhat new to bash, so I'm still trying to figure out why it works, but it does nonetheless! Thanks again! Commented Jul 24, 2016 at 16:21
1

Actually, the regexp

([0-9]+:.{1,}state UP.{1,}(\n.{1,}?){1,}inet )\K([0-9]{1,3}\.?){4}

which you first presented, works, with an appropriate environment and Perl:

$ perl -l -0 -ne 'print $& if /([0-9]+:.{1,}state UP.{1,}(\n.{1,}?){1,}inet )\K([0-9]{1,3}\.?){4}/'  < output_of_your_ip_addr
192.168.1.100

-0 reads the file in full (instead of line-by-line), and $& contains the matching part (what is left after \K drops the left part) .


Though if Perl is usable, I would just write

ip addr | perl -l -0ne  'print $1 while /state UP.*?inet ([0-9.]+)/sg'

to print all matches. (Change while to if to only take the first match. $1 contains what the first () matched.)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .