-1

Trying to get only the lines with ipv4 addresses in the $networks variable.

#!/bin/bash

ivp4_pattern='/^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$/igm'
networks=$(ip addr | grep "inet" | awk '{print $2}')

while read -r line; 
do
    echo "$line"
done <<< "$networks"

echo "$ivp4_pattern"
echo "$networks" | grep "$ivp4_pattern"

Output:

[jonathan@localhost ~]$ ./script.sh 
127.0.0.1/8
::1/128
172.16.155.128/24
fe80::da84:977a:d654:7716/64
/^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$/igm

Tried removing the / and with -E...

#!/bin/bash

ivp4_pattern="'^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$'"
networks=$(ip addr | grep "inet" | awk '{print $2}')

while read -r line; 
do
    echo "$line"
done <<< "$networks"

echo $ivp4_pattern
echo $networks | grep -E $ivp4_pattern

Also tried loop through networks line by line and taking the regex out of the variable...

#!/bin/bash

networks=$(ip addr | grep "inet" | awk '{print $2}')

while read -r line; 
do
    echo "$line"
done <<< "$networks"

while read -r line;
do
    echo $line
    echo $line | grep '^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$'
done <<< "$networks"

I got it working adding -E to grep without regex in variable...but why is it working? It doesn't like the regex being in a variable?

#!/bin/bash

networks=$(ip addr | grep "inet" | awk '{print $2}')

while read -r line; 
do
    echo "$line"
done <<< "$networks"

while read -r line;
do
    # echo $line
    echo $line | grep -E '^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$'
done <<< "$networks"
~                             
Jonathan Kittell
  • 7,163
  • 15
  • 50
  • 93
  • 2
    That looks like `perl` regex syntax. If you want to use it with `grep`, you need to use POSIX "basic regular expression" syntax. Alternately, you could use `grep -E` and "extended regular expression" syntax. Either way, the `/ /` delimiters and options at the end need to go away -- those aren't part of the regex at all, they're perl syntax for *using* a regex. – Gordon Davisson Feb 20 '19 at 20:45
  • https://stackoverflow.com/questions/5284147/validating-ipv4-addresses-with-regexp ?? – KamilCuk Feb 20 '19 at 21:32
  • 2
    Also tangentially avoid the [useless use of `grep`](http://www.iki.fi/era/unix/award.html#grep): `ip addr | awk '/inet/ { print $2 }'` ... Though perhaps your entire script should be in Awk, and only slightly longer than this. – tripleee Feb 20 '19 at 21:34

2 Answers2

1

As a bash solution, how about:

ipv4_pattern="([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})"
ip addr | while read -r line; do
    if [[ $line =~ inet\ $ipv4_pattern ]]; then
        echo "${BASH_REMATCH[1]}"
    fi
done

Note that the while loop above is invoked in the child process and variables assigned here are inaccessible from the parent. In such a case, please make use of a process substitution as;

ipv4_pattern="([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})"
while read -r line; do
    if [[ $line =~ inet\ $ipv4_pattern ]]; then
        echo "${BASH_REMATCH[1]}"
        # do some assignments here as ip_list+=("${BASH_REMATCH[1]}")
    fi
done < <(ip addr)

Hope this helps.

tshiono
  • 21,248
  • 2
  • 14
  • 22
1

If you want to list only IPv4 addresses, how about this?

The first ...

#!/bin/bash

#
# ip addr         : list IP info. 
# grep "inet "    : Only for IPv4. IPv6 addresses are listed up with "inet6".
# awk '{print $2}': Extract IPv4 adress
ipaddrs=$(ip addr | grep "inet " | awk '{print $2}')

while read -r ipaddr
do
  echo $(cut -d"/" -f1 <<< ${ipaddr})
done <<< "${ipaddrs}"

exit 0

The Second is ...

#!/bin/bash

#
# ip addr         : list IP info. 
# grep "inet "    : Only for IPv4. IPv6 addresses are listed up with "inet6".
ipaddrs=$(ip addr | grep "inet ")

while read -r ipaddr
do
    # sample: inet 100.52.62.173/24 brd 100.52.62.255 scope global bond1
    ipv4_cidr=$(cut -d" " -f2 <<< ${ipaddr})
    ipv4=$(cut -d"/" -f1 <<< ${ipv4_cidr})
    netmask=$(cut -d"/" -f2 <<< ${ipv4_cidr})
    brdcast=$(cut -d" " -f4 <<< ${ipaddr})

    echo "----------------------------"
    echo "============================"
    echo "ip addr   : ${ipaddr}"
    echo "----------------------------"
    echo "IP Address: ${ipv4}"
    echo "Netmask   : ${netmask}"
    echo "Broadcast : ${brdcast}"

done <<< "${ipaddrs}"

exit 0

The third is ...

#!/bin/bash

#
# ip addr         : list IP info. 
# grep "inet "    : Only for IPv4. IPv6 addresses are listed up with "inet6".
ipaddrs=$(ip addr | grep "inet ")

while IFS=" " read -ra ipaddr
do
    # If a first line is "inet 100.52.62.173/24 brd 100.52.62.255 scope global bond1"
    # 1. ipadddr is (inet 100.52.62.173/24 brd 100.52.62.255 scope global bond1)
    # A second is cidr.
    IFS="/" read -ra ipv4_cidr <<< "${ipaddr[1]}"
    # 2. ipv4_cidr is ("100.52.62.173" "24")
    ipv4="${ipv4_cidr[0]}"
    netmask="${ipv4_cidr[1]}"
    # A fourth is 'broadcast'.
    brdcast="${ipaddr[3]}"

    echo "----------------------------"
    echo "============================"
    echo "ip addr   : ${ipaddr[@]}"
    echo "----------------------------"
    echo "IP Address: ${ipv4}"
    echo "Netmask   : ${netmask}"
    echo "Broadcast : ${brdcast}"

done <<< "${ipaddrs}"

exit 0

Park Jun-Hong
  • 103
  • 1
  • 6