Bash - Convert netmask in CIDR notation?
Asked Answered
M

4

8

Example: I have this netmask: 255.255.255.0

Is there, in bash, a command or a simple script to convert my netmask in notation /24?

Matsumoto answered 18/5, 2018 at 14:27 Comment(1)
Simple Python script (not posting as an answer because of that): import ipaddress,math;print("/" + str(32-math.ceil(math.log2(int(ipaddress.IPv4Address(input()))^2**32-1))))Pentothal
G
7

Example Function for RHEL6/RHEL7:

IPprefix_by_netmask() {
#function returns prefix for given netmask in arg1
 ipcalc -p 1.1.1.1 $1 | sed -n 's/^PREFIX=\(.*\)/\/\1/p'
}

The Result:

$ IPprefix_by_netmask 255.255.255.0
/24

In other Linux distributives ipcalc options may differ.

The same function without ipcalc, tested in Solaris and Linux:

IPprefix_by_netmask() {
    #function returns prefix for given netmask in arg1
    bits=0
    for octet in $(echo $1| sed 's/\./ /g'); do 
         binbits=$(echo "obase=2; ibase=10; ${octet}"| bc | sed 's/0//g') 
         let bits+=${#binbits}
    done
    echo "/${bits}"
}
Galleywest answered 18/5, 2018 at 15:21 Comment(3)
The ipcalc version of the function outputs nothing on my system, (Lubuntu v17.10). Running ipcalc -p 1.1.1.1 255.255.255.0 returns an "Unknown option: -p" error. ipcalc version is 0.41-5.Mellifluous
This works: ipcalc -n 1.1.1.1 $1 | sed -n '/^Netm/{s#.*= #/#;s/ .*//p;q}'Mellifluous
or ipcalc -nb 1.1.1.1 "$1" | sed -n '/Netmask/s/^.*=[ ]/\//pBaneful
M
8
  1. Function using subnetcalc:

    IPprefix_by_netmask() {
        subnetcalc 1.1.1.1 "$1" -n  | sed -n '/^Netw/{s#.*/ #/#p;q}'
    }
    
  2. In pure bash, (i.e. no external utils like sed or bc), convert IP to a long octal string and sum its bits:

    IPprefix_by_netmask () { 
       c=0 x=0$( printf '%o' ${1//./ } )
       while [ $x -gt 0 ]; do
           let c+=$((x%2)) 'x>>=1'
       done
       echo /$c ; }
    

Output of IPprefix_by_netmask 255.255.255.0 (either function):

/24
Mellifluous answered 18/5, 2018 at 22:19 Comment(2)
It's worth noting that the portability of ipcalc and sipcalc is a little better than that of subnetcalc due to better availability, according to pkgs.org. You may wish to take this into account.Agrigento
Among the distros I use and tested: Arch has ipcalc and sipcalc in its official repo, while subnetcalc is only available from the AUR; RHEL 8 and derivatives (with EPEL enabled) similarly have both ipcalc and sipcalc but not subnetcalc.Agrigento
G
7

Example Function for RHEL6/RHEL7:

IPprefix_by_netmask() {
#function returns prefix for given netmask in arg1
 ipcalc -p 1.1.1.1 $1 | sed -n 's/^PREFIX=\(.*\)/\/\1/p'
}

The Result:

$ IPprefix_by_netmask 255.255.255.0
/24

In other Linux distributives ipcalc options may differ.

The same function without ipcalc, tested in Solaris and Linux:

IPprefix_by_netmask() {
    #function returns prefix for given netmask in arg1
    bits=0
    for octet in $(echo $1| sed 's/\./ /g'); do 
         binbits=$(echo "obase=2; ibase=10; ${octet}"| bc | sed 's/0//g') 
         let bits+=${#binbits}
    done
    echo "/${bits}"
}
Galleywest answered 18/5, 2018 at 15:21 Comment(3)
The ipcalc version of the function outputs nothing on my system, (Lubuntu v17.10). Running ipcalc -p 1.1.1.1 255.255.255.0 returns an "Unknown option: -p" error. ipcalc version is 0.41-5.Mellifluous
This works: ipcalc -n 1.1.1.1 $1 | sed -n '/^Netm/{s#.*= #/#;s/ .*//p;q}'Mellifluous
or ipcalc -nb 1.1.1.1 "$1" | sed -n '/Netmask/s/^.*=[ ]/\//pBaneful
R
6

Solution based on awk

While GNU awk is not Bash, it’s installed by default in enough distributions that this may be helpful in the sense of the question:

awk -F. '{
    split($0, octets)
    for (i in octets) {
        mask += 8 - log(2**8 - octets[i])/log(2);
    }
    print "/" mask
}' <<< 255.255.255.240

This prints:

/28
Roquelaure answered 2/3, 2021 at 12:8 Comment(1)
I hat to replace the 2**8 with 2^8, otherwise I got awk: line 4: syntax error at or near *. However this is on Debian 12 which comes with mawk.Magistery
T
1

Based on Sasha's answer, this script works with dash (tested with Ubuntu 18.04):

IPprefix_by_netmask() {
    #function returns prefix for given netmask in arg1
    bits=0
    for octet in $(echo $1| sed 's/\./ /g'); do 
         binbits=$(echo "obase=2; ibase=10; ${octet}"| bc | sed 's/0//g') 
         bits=$(expr $bits + ${#binbits})
    done
    echo "/${bits}"
}
Torsibility answered 18/12, 2019 at 0:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.