How to read file, and replace certain string with another string?

Hi all, the value in the following file is just an example. It could be a different value/network addresses.

Here is my example of initial output in a file name net.txt

Initial Output, net.txt

The goal is to produce the following format which is to convert from CIDR to Netmask formatting.

My current draft script which is not perfect is to use �sed� to replace �/24� with �255.255.255.0� format. This is part of network subnetting conversion.

This is to print the initial net.txt value and save the final output to net-mask.txt

or

Or course the sed script for CIDR to netmask table above is not complete. The full list of the conversion can be found here. Netmask / CIDR Translation Table

Please let me know where is the best place to put �sed� into my shell script file.
If there is better way to do this, please let me know. Thanks in advance.

Hello type8code0,

Following may help you in same.

 awk -F"/" '{sub("8","255.0.0.0",$2);sub("16","255.255.0.0",$2);sub("24","255.255.255.0",$2);print}' Input_file

Output will be as follows.

10.0.0.0 255.0.0.0
172.16.1.0 255.255.0.0
192.168.1.0 255.255.255.0

EDIT: Also kindly use code tags for commands and codes not quotes, quotes you can use to address any user's speicific post etc purposes like I have used above for your post, you can go through the forum rules in below link.

Thanks,
R. Singh

1 Like

There is a syntax error in the above code: The quote in front of $1 is superfluous.
Apart from that, in this particular case (input file contains only one column) the above code is essentially the same as cp net.txt net-mask.txt :cool:

If you plan to use it for modification of net-mask.txt, then it certainly should be placed below the awk command.

#!/bin/bash
awk '{
print $1;
}' net.txt > net-mask.txt

sed -i 's/\/8/ 255.0.0.0/' net-mask.txt
sed -i 's/\/16/ 255.255.0.0/' net-mask.txt
sed -i 's/\/24/ 255.255.255.0/' net-mask.txt

Note I used sed 's -i option for inplace editing, otherwise things get complicated, e.g.

sed 's/\/8/ 255.0.0.0/' net-mask.txt > net-mask.temp
mv net-mask.temp net-mask.txt
sed 's/\/16/ 255.255.0.0/' net-mask.txt > net-mask.temp
mv net-mask.temp net-mask.txt
sed 's/\/24/ 255.255.255.0/' net-mask.txt > net-mask.temp
mv net-mask.temp net-mask.txt

Sure.

#!/bin/bash

awk -F'/' '
    $2==8  { print $1 " 255.0.0.0" }
    $2==16 { print $1 " 255.255.0.0" }
    $2==24 { print $1 " 255.255.255.0" }
' net.txt > net-mask.txt

I think you get the idea now and will be able to extend this code to match other CIDRs :b:

1 Like

This task is almost impossible in awk as it doesn't have bit operations. But, in (recent) bash, you could try this:

while IFS="/" read A B
        do DL=$'\t'
           printf "%s/%s" $A $B 
           for i in 24 16 8 0
                do printf "%s%d" "$DL" $(((2**32-1 ^ (2**(32-B)-1) >> $i) & 255))
                   DL="."
                done
           printf "\n"
        done < file
10.0.0.0/8        255.0.0.0
10.0.0.0/10       255.192.0.0
172.16.1.0/16     255.255.0.0
172.16.1.0/18     255.255.192.0
192.168.1.0/24    255.255.255.0
192.168.1.0/32    255.255.255.255
1 Like

My original solution, from your original thread, still does exactly what you say you want. Did you ever try it?

#!/bin/bash

while IFS="/" read IP S
do
        M=$(( 0xffffffff ^ ((1 << (32-S)) -1) ))
        echo "$IP netmask $(( (M>>24) & 0xff )).$(( (M>>16) & 0xff )).$(( (M>>8) & 0xff )).$(( M & 0xff ))"
done < infile > outfile
1 Like

Cool. I�ll just need to add the rest of CIDR to Netmask conversion.
I�ll share the full bash script later once it�s complete.
I�ll take note on code vs quotes. Thanks again I really appreciate it. :b:

Here is the sample of the output.

me@box:~/$ cat net.txt
10.0.0.0/8
172.16.1.0/16
192.168.1.0/24
me@box:~/$ awk -F"/" '{sub("8","255.0.0.0",$2);sub("16","255.255.0.0",$2);sub("24","255.255.255.0",$2);print}' net.txt
10.0.0.0 255.0.0.0
172.16.1.0 255.255.0.0
192.168.1.0 255.255.255.0
me@box:~/$

---------- Post updated at 01:22 AM ---------- Previous update was at 01:09 AM ----------

Awesome! You�re definitely senior-helper. Thanks again for your help I really appreciate it.

Here is the full code. Hopefully others will get benefit from this too.

#!/bin/bash
################################################
# Credit and special thanks to "junior-helper": 
# Usage: ./cidr2subnet-junior-helper
################################################

awk -F'/' '
$2== 32 { print $1 " 255.255.255.255 " }
$2== 31 { print $1 " 255.255.255.254 " }
$2== 30 { print $1 " 255.255.255.252 " }
$2== 29 { print $1 " 255.255.255.248 " }
$2== 28 { print $1 " 255.255.255.240 " }
$2== 27 { print $1 " 255.255.255.224 " }
$2== 26 { print $1 " 255.255.255.192 " }
$2== 25 { print $1 " 255.255.255.128 " }
$2== 24 { print $1 " 255.255.255.0 " }
$2== 23 { print $1 " 255.255.254.0 " }
$2== 22 { print $1 " 255.255.252.0 " }
$2== 21 { print $1 " 255.255.248.0 " }
$2== 20 { print $1 " 255.255.240.0 " }
$2== 19 { print $1 " 255.255.224.0 " }
$2== 18 { print $1 " 255.255.192.0 " }
$2== 17 { print $1 " 255.255.128.0 " }
$2== 16 { print $1 " 255.255.0.0 " }
$2== 15 { print $1 " 255.254.0.0 " }
$2== 14 { print $1 " 255.252.0.0 " }
$2== 13 { print $1 " 255.248.0.0 " }
$2== 12 { print $1 " 255.240.0.0 " }
$2== 11 { print $1 " 255.224.0.0 " }
$2== 10 { print $1 " 255.192.0.0 " }
$2== 9 { print $1 " 255.128.0.0 " }
$2== 8 { print $1 " 255.0.0.0 " }
$2== 7 { print $1 " 254.0.0.0 " }
$2== 6 { print $1 " 252.0.0.0 " }
$2== 5 { print $1 " 248.0.0.0 " }
$2== 4 { print $1 " 240.0.0.0 " }
$2== 3 { print $1 " 224.0.0.0 " }
$2== 2 { print $1 " 192.0.0.0 " }
$2== 1 { print $1 " 128.0.0.0 " }
' net.txt > net-mask.txt

And here is the output

me@box:~/$ cat net.txt
10.0.0.0/8
172.16.1.0/16
192.168.1.0/24
me@box:~/$

me@box:~/$ ./cidr2subnet-junior-helper

me@box:~/$ cat net-mask.txt
10.0.0.0 255.0.0.0
172.16.1.0 255.255.0.0
192.168.1.0 255.255.255.0
me@box:~/$

Next project is to reverse this process which is to convert from netmask to CIDR form :cool:

---------- Post updated at 01:34 AM ---------- Previous update was at 01:22 AM ----------

Many thanks RudiC :b:
This forum is super cool. One question, multiple solutions provided and each of them is unique.
And here is the output

me@box:~/$ cat net.txt
10.0.0.0/8
172.16.1.0/16
192.168.1.0/24
me@box:~/$
me@box:~/$ cat ./cidr2subnet-RudiC
################################################
# Credit and special thanks to "RudiC":
# Usage: ./cidr2subnet-RudiC
################################################

while IFS="/" read A B
        do DL=$'\t'
           printf "%s/%s" $A $B
           for i in 24 16 8 0
                do printf "%s%d" "$DL" $(((2**32-1 ^ (2**(32-B)-1) >> $i) & 255))
                   DL="."
                done
           printf "\n"
        done < net.txt
me@box:~/$

me@box:~/$ ./cidr2subnet-RudiC
10.0.0.0/8      255.0.0.0
172.16.1.0/16   255.255.0.0
192.168.1.0/24  255.255.255.0
me@box:~/$

I just have one question on this script. Is it possible to remove /8,/16, and /24 from the output and use a space instead of tab?
Please let me know if there is a way to reverse this process from CIDR to netmask formatting.

Example:
Initial Input

Final Output

---------- Post updated at 01:52 AM ---------- Previous update was at 01:34 AM ----------

Your solution is perfect. Thanks again. I noticed you've added "< infile > outfile" to this script. I'm new to the shell script and it's so fun learning it by solving daily problem and make things easier.

I've updated the input and output file name and here is the sample of the output. Please let me know how to reverse this process as well from netmask to CIDR formatting.

me@box:~/$ cat net.txt
10.0.0.0/8
172.16.1.0/16
192.168.1.0/24
me@box:~/$
me@box:~/$ cat cidr2subnet-Corona688
#!/bin/bash

################################################
# Credit and special thanks to "Corona688":
# Usage: ./cidr2subnet-Corona688
################################################

while IFS="/" read IP S
do
        M=$(( 0xffffffff ^ ((1 << (32-S)) -1) ))
        echo "$IP $(( (M>>24) & 0xff )).$(( (M>>16) & 0xff )).$(( (M>>8) & 0xff )).$(( M & 0xff ))"
done < net.txt > net-mask.txt
me@box:~/$
me@box:~/$ ./cidr2subnet-Corona688
me@box:~/$
me@box:~/$ cat net-mask.txt
10.0.0.0 255.0.0.0
172.16.1.0 255.255.0.0
192.168.1.0 255.255.255.0
me@box:~/$

To remove the /nn, replace printf "%s/%s" $A $B by printf "%s" $A
For the reverse operation, try

while IFS="     ." read -a VAL
          do N=0
             DL=( . . . / )
             for ((J=0;J<=3;J++))
                  do printf "%d%s" ${VAL[J]} "${DL[J]}"
                     for ((I=7;I>=0;I--))
                          do N=$(( N + (VAL[J+4]>>I)%2 ))
                          done
                  done
             printf "%d\n" $N
          done < file
10.0.0.0/8
10.0.0.0/10
172.16.1.0/16
172.16.1.0/17
172.16.1.0/18
172.16.1.0/19
192.168.1.0/24
192.168.1.0/32
1 Like