linux shell netmask2cdir和cdir2netmask中cidr到netmask的转换器的说明

MOH*_*MED 17 linux bash shell sh

我在本主题中找到了以下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}
}
Run Code Online (Sandbox Code Playgroud)

你能详细解释一下这些函数如何将cidr转换为网络掩码,将网络掩码转换为cidr?具体来说,调用set,参数扩展${#…}和算术扩展$((…))非常庞大.

Thi*_*Not 28

mask2cdr()

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

255.255.192.0
Run Code Online (Sandbox Code Playgroud)

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

11111111.11111111.11000000.00000000  # 18 ones = /18 in CIDR
Run Code Online (Sandbox Code Playgroud)

这个功能相当创造性地做到了.首先,我们剥离所有前导255八位字节(即二进制中的所有八位字节)并将结果存储在变量中x:

local x=${1##*255.}
Run Code Online (Sandbox Code Playgroud)

此步骤使用参数扩展,整个脚本非常依赖它.如果我们继续使用示例网络掩码255.255.192.0,我们现在有以下值:

$1: 255.255.192.0
$x: 192.0
Run Code Online (Sandbox Code Playgroud)

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

set -- foo bar  # $1 = foo, $2 = bar
Run Code Online (Sandbox Code Playgroud)

我更喜欢使用命名变量而不是位置参数,因为它使脚本更易于阅读和调试,但最终结果是相同的.我们设定$1为:

0^^^128^192^224^240^248^252^254^
Run Code Online (Sandbox Code Playgroud)

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

我们设定$2

$(( (${#1} - ${#x})*2 ))
Run Code Online (Sandbox Code Playgroud)

这称为算术扩展.它看起来很复杂,但它实际上只是计算1我们在第一个命令中剥离的位数.它分解为:

(number of chars in $1 - number of chars in $x) * 2
Run Code Online (Sandbox Code Playgroud)

在我们的案例中,这是有用的

(13 - 5) * 2 = 16
Run Code Online (Sandbox Code Playgroud)

我们剥离了两个八位字节,所以我们得到了16个.

我们设定$3为:

${x%%.*}
Run Code Online (Sandbox Code Playgroud)

这是$x第一次.被剥离后所有东西的价值.在我们的例子中,这是192.

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

0^^^  128^  192^  224^  240^  248^  252^  254^
Run Code Online (Sandbox Code Playgroud)

在二进制中,以上数字是:

00000000 10000000 11000000 11100000 11110000 11111000 11111100 11111110
# 0 ones 1 one    2 ones   3 ones   ...
Run Code Online (Sandbox Code Playgroud)

如果我们从左边开始计数,则表中的每个四字符块对应1于二进制的附加位.我们正在尝试转换192,所以让我们首先从表中删除最右边的部分192,并将其存储在x:

x=${1%%$3*}
Run Code Online (Sandbox Code Playgroud)

价值$x现在是

0^^^128^
Run Code Online (Sandbox Code Playgroud)

它包含两个四字符块,或1二进制两位.

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

echo $(( $2 + (${#x}/4) ))
Run Code Online (Sandbox Code Playgroud)

哪里

${#x}/4
Run Code Online (Sandbox Code Playgroud)

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

输出:

18
Run Code Online (Sandbox Code Playgroud)

cdr2mask()

让我们继续运行前面的例子,它的CIDR前缀为18.

我们使用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
Run Code Online (Sandbox Code Playgroud)

让我们来看看用于设置的公式$1$6更接近的公式.$1被设置为:

$(( 5 - ($1 / 8) ))
Run Code Online (Sandbox Code Playgroud)

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

11111111.11111111.11111111.11111111
Run Code Online (Sandbox Code Playgroud)

和0表示网络掩码

00000000.00000000.00000000.00000000
Run Code Online (Sandbox Code Playgroud)

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

5 - (32 / 8) = 1
5 - ( 0 / 8) = 5
Run Code Online (Sandbox Code Playgroud)

$6 被设置为:

$(( (255 << (8 - ($1 % 8))) & 255 ))
Run Code Online (Sandbox Code Playgroud)

让我们为我们的示例CIDR前缀打破这个18.首先我们取模数并做一些减法:

8 - (18 % 8) = 6
Run Code Online (Sandbox Code Playgroud)

接下来,我们按位移位255:

255 << 6
Run Code Online (Sandbox Code Playgroud)

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

11111111000000
Run Code Online (Sandbox Code Playgroud)

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

11111111000000 &
00000011111111  # 255
Run Code Online (Sandbox Code Playgroud)

这使

00000011000000
Run Code Online (Sandbox Code Playgroud)

或者干脆

11000000
Run Code Online (Sandbox Code Playgroud)

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

11111111.11111111.11000000.00000000
                  ^------^
Run Code Online (Sandbox Code Playgroud)

在十进制中,值为192.

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

[ $1 -gt 1 ] && shift $1 || shift
Run Code Online (Sandbox Code Playgroud)

在我们的例子中,值$1是3,所以我们将位置参数3移到左边.之前的值$4变为新值$1,之前的值$5变为值$2,依此类推:

$1: 255
$2: 255
$3: 192
$4: 0
$5: 0
$6: 0
Run Code Online (Sandbox Code Playgroud)

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

echo ${1-0}.${2-0}.${3-0}.${4-0}
Run Code Online (Sandbox Code Playgroud)

-0每个参数后表示使用0作为默认值,如果参数没有设置.

输出:

255.255.192.0
Run Code Online (Sandbox Code Playgroud)

  • 精彩.很好解释非常感谢你 (3认同)
  • 这是一个很好的答案。我用它作为将“代码高尔夫”形式转换为更详细的“变量名称作为文档”形式的基础。您可以在这个要点中看到这一点:https://gist.github.com/RichardBronosky/7902f062ab36d3c99413ba21986ed0cb (2认同)