在linux shell netmask2cdir和cdir2netmask中将cidr转换为networking掩码的说明

我从这个主题find了下面的shell函数

mask2cdr () { # Assumes there's no "255." after a non-255 byte in the mask local x=${1##*255.} set -- 0^^^128^192^224^240^248^252^254^ $(( (${#1} - ${#x})*2 )) ${x%%.*} x=${1%%$3*} echo $(( $2 + (${#x}/4) )) } cdr2mask () { # Number of args to shift, 255..255, first non-255 byte, zeroes set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0 [ $1 -gt 1 ] && shift $1 || shift echo ${1-0}.${2-0}.${3-0}.${4-0} } 

你能详细解释一下这些函数如何将cidr转换为networking掩码,将networking掩码转换为cidr? 我无法理解代码。

Solutions Collecting From Web of "在linux shell netmask2cdir和cdir2netmask中将cidr转换为networking掩码的说明"

mask2cdr()

从像这样的点十进制网络掩码获取CIDR前缀:

 255.255.192.0 

您首先必须将四个八位字节转换为二进制数,然后计算最高有效位(即最高有效位数):

 11111111.11111111.11000000.00000000 # 18 ones = /18 in CIDR 

这个功能相当有创意。 首先,我们去除所有的前255个八位字节(即二进制全为1的八位字节),并将结果存储在变量x

 local x=${1##*255.} 

这一步使用参数扩展 ,整个脚本非常依赖。 如果我们继续我们的例子255.255.192.0网络掩码,我们现在有以下值:

 $1: 255.255.192.0 $x: 192.0 

接下来我们设置三个变量: $1$2$3 。 这些被称为位置参数 ; 它们很像普通的命名变量,但通常在将参数传递给脚本或函数时进行设置。 我们可以直接使用set --来设置值,例如:

 set -- foo bar # $1 = foo, $2 = bar 

我更喜欢在位置参数上使用命名变量,因为它使脚本更容易读取和调试,但最终结果是相同的。 我们将$1设置为:

 0^^^128^192^224^240^248^252^254^ 

这实际上只是一个将某些十进制值转换为二进制值并计算1位数的表格。 我们稍后再回来。

我们设置$2

 $(( (${#1} - ${#x})*2 )) 

这看起来很复杂,但它实际上只是计算我们在第一个命令中删除的1位的数量。 它分解为:

 (number of chars in $1 - number of chars in $x) * 2 

这在我们的案例中是可行的

 (13 - 5) * 2 = 16 

我们剥去了两个八位字节,所以我们得到了十六个。

我们将$3设置为:

 ${x%%.*} 

这是$x与第一个之后的所有东西的价值. 剥去。 在我们的情况下,这是192

我们需要将这个数字转换为二进制数,并计算其中的1位数,所以让我们回到我们的“转换表”。 我们可以将表格分成相等的四个字符块:

 0^^^ 128^ 192^ 224^ 240^ 248^ 252^ 254^ 

在二进制中,上面的数字是:

 00000000 10000000 11000000 11100000 11110000 11111000 11111100 11111110 # 0 ones 1 one 2 ones 3 ones ... 

如果从左数起,表中的每个四字符块对应于二进制的附加1位。 我们试图转换192 ,所以我们首先从192开始,把表的最右边部分放掉,然后把它存储在x

 x=${1%%$3*} 

$x的价值是现在

 0^^^128^ 

其中包含两个四字符块,或二进制的两个1位。

现在,我们只需要从前255个八位字节(总计16个,存储在变量$2 )和上一个步骤(共$2 )中的1位中加起来:

 echo $(( $2 + (${#x}/4) )) 

哪里

 ${#x}/4 

$x的字符数除以4,即$x的四个字符块的数量。

输出:

 18 

cdr2mask()

让我们继续运行我们以前的例子,它有一个18的CIDR前缀。

我们使用set --来设置位置参数$ 1到$ 9:

 $1: $(( 5 - ($1 / 8) )) # 5 - (18 / 8) = 3 [integer math] $2: 255 $3: 255 $4: 255 $5: 255 $6: $(( (255 << (8 - ($1 % 8))) & 255 )) # (255 << (8 - (18 % 8))) & 255 = 192 $7: 0 $8: 0 $9: 0 

让我们来看看用来设置$1$6的公式。 $1被设置为:

 $(( 5 - ($1 / 8) )) 

对于网络掩码,CIDR前缀的最大和最小可能值是32

 11111111.11111111.11111111.11111111 

和0的网络掩码

 00000000.00000000.00000000.00000000 

上面的公式使用整数除法,因此可能的结果范围从1到5:

 5 - (32 / 8) = 1 5 - ( 0 / 8) = 5 

$6被设置为:

 $(( (255 << (8 - ($1 % 8))) & 255 )) 

我们来分析一下18 CIDR前缀。 首先我们取模量,做一些减法:

 8 - (18 % 8) = 6 

接下来我们按位移255这个值:

 255 << 6 

这与在二进制中将六个0位推到255的末尾相同:

 11111111000000 

最后,我们按位与这个值255:

 11111111000000 & 00000011111111 # 255 

这使

 00000011000000 

或干脆

 11000000 

看起来熟悉? 这是我们在二进制网络掩码中的第三个八位字节:

 11111111.11111111.11000000.00000000 ^------^ 

在十进制中,值是192。

接下来我们根据$1的值来移动位置参数:

 [ $1 -gt 1 ] && shift $1 || shift 

在我们的例子中, $1的值是3,所以我们将位置参数3移到左边。 前一个$4的值变成$1的新值, $1的前一个值变成$2的值,以此类推:

 $1: 255 $2: 255 $3: 192 $4: 0 $5: 0 $6: 0 

这些值应该看起来很熟悉:它们是来自我们的网络掩码的十进制八位字节(在最后附加了几个额外的零)。 为了获得网络掩码,我们只需打印出前四个点之间的点:

 echo ${1-0}.${2-0}.${3-0}.${4-0} 

如果参数未设置,则每个参数之后的-0表示使用0作为默认值。

输出:

 255.255.192.0