bash linux shell netmask2cdir和cdir2netmask中cidr to netmask的convertor说明
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20762575/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Explanation of convertor of cidr to netmask in linux shell netmask2cdir and cdir2netmask
提问by MOHAMED
I found the following shell functions from this topic
我从这个主题中找到了以下 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%%*}
echo $(( + (${#x}/4) ))
}
cdr2mask ()
{
# Number of args to shift, 255..255, first non-255 byte, zeroes
set -- $(( 5 - ( / 8) )) 255 255 255 255 $(( (255 << (8 - ( % 8))) & 255 )) 0 0 0
[ -gt 1 ] && shift || shift
echo ${1-0}.${2-0}.${3-0}.${4-0}
}
Could you explain in details how these functions convert cidr to netmask and the netmask to cidr? Specifically, the calls to set
, the parameter expansion ${#…}
, and the arithmetic expansion $((…))
are quite overwhelming.
你能详细解释一下这些函数是如何将cidr转换为网络掩码以及将网络掩码转换为cidr的吗?具体来说,对 的调用set
、参数扩展${#…}
和算术扩展$((…))
非常庞大。
回答by ThisSuitIsBlackNot
mask2cdr()
掩码2cdr()
To get the CIDR prefix from a dot-decimal netmask like this one:
要从这样的点十进制网络掩码中获取 CIDR 前缀:
255.255.192.0
you first have to convert the four octets to binary and then count the most significant bits (i.e. the number of leading ones):
您首先必须将四个八位字节转换为二进制,然后计算最高有效位(即前导位的数量):
11111111.11111111.11000000.00000000 # 18 ones = /18 in CIDR
This function does that rather creatively. First, we strip off all of the leading 255
octets (i.e. the octets that are all ones in binary) and store the results in variable x
:
这个功能相当有创意地做到了这一点。首先,我们去除所有前导255
八位字节(即二进制中都是 1 的八位字节)并将结果存储在变量中x
:
local x=${1##*255.}
This step uses parameter expansion, which the entire script relies on pretty heavily. If we continue with our example netmask of 255.255.192.0
, we now have the following values:
这一步使用了整个脚本非常依赖的参数扩展。如果我们继续我们的示例网络掩码255.255.192.0
,我们现在有以下值:
: 255.255.192.0
$x: 192.0
Next we set three variables: $1
, $2
, and $3
. These are called positional parameters; they are much like ordinary named variables but are typically set when you pass arguments to a script or function. We can set the values directly using set --
, for example:
接下来我们设置了三个变量:$1
,$2
,和$3
。这些被称为位置参数;它们很像普通的命名变量,但通常在您将参数传递给脚本或函数时设置。我们可以直接使用 设置值set --
,例如:
set -- foo bar # = foo, = bar
I prefer using named variables over positional parameters since it makes scripts easier to read and debug, but the end result is the same. We set $1
to:
我更喜欢使用命名变量而不是位置参数,因为它使脚本更易于阅读和调试,但最终结果是相同的。我们设置$1
为:
0^^^128^192^224^240^248^252^254^
This is really just a table to convert certain decimal values to binary and count the number of 1
bits. We'll come back to this later.
这实际上只是一个将某些十进制值转换为二进制并计算位数的表格1
。我们稍后会回到这个话题。
We set $2
to
我们设置$2
为
$(( (${#1} - ${#x})*2 ))
This is called Arithmetic Expansion. It looks complex, but it is really just counting the number of 1
bits we stripped off in the first command. It breaks down to this:
这称为算术扩展。它看起来很复杂,但实际上只是计算1
我们在第一个命令中剥离的位数。它分解为:
(number of chars in - number of chars in $x) * 2
which in our case works out to
在我们的例子中
(13 - 5) * 2 = 16
We stripped off two octets so we get 16. Makes sense.
我们去掉了两个八位字节,所以我们得到了 16 个。有道理。
We set $3
to:
我们设置$3
为:
${x%%.*}
which is the value of $x
with everything after the first .
stripped off. In our case, this is 192
.
这是$x
第一次.
剥离后所有东西的价值。在我们的例子中,这是192
.
We need to convert this number to binary and count the number of 1
bits in it, so let's go back to our "conversion table." We can divide the table into equal chunks of four characters each:
我们需要将这个数字转换为二进制并计算其中的1
位数,所以让我们回到我们的“转换表”。我们可以将表分成相等的块,每块四个字符:
0^^^ 128^ 192^ 224^ 240^ 248^ 252^ 254^
In binary, the above numbers are:
在二进制中,上述数字是:
00000000 10000000 11000000 11100000 11110000 11111000 11111100 11111110
# 0 ones 1 one 2 ones 3 ones ...
If we count from the left, each four-character block in the table corresponds to an additional 1
bit in binary. We're trying to convert 192
, so let's first lop off the rightmost part of the table, from 192
on, and store it in x
:
如果我们从左边数起,表格中的每个四字符块都对应一个额外1
的二进制位。我们正在尝试转换192
,所以让我们首先从表的最右边部分192
开始,然后将其存储在x
:
x=${1%%*}
The value of $x
is now
的价值$x
是现在
0^^^128^
which contains two four-character blocks, or two 1
bits in binary.
它包含两个四字符块,或1
二进制的两位。
Now we just need to add up the 1
bits from our leading 255
octets (16 total, stored in variable $2
) and the 1
bits from the previous step (2 total):
现在我们只需要将1
前导255
八位字节中的位(总共 16 个,存储在变量中$2
)和1
上一步中的位(总共 2 个)相加:
echo $(( + (${#x}/4) ))
where
在哪里
${#x}/4
is the number of characters in $x
divided by four, i.e. the number of four-character blocks in $x
.
是 in$x
除以 4 的字符数,即 中的四字符块数$x
。
Output:
输出:
18
cdr2mask()
cdr2mask()
Let's keep running with our previous example, which had a CIDR prefix of 18
.
让我们继续之前的示例,它的 CIDR 前缀为18
.
We use set --
to set positional parameters $1 through $9:
我们set --
用来设置位置参数 $1 到 $9:
: $(( 5 - ( / 8) )) # 5 - (18 / 8) = 3 [integer math]
: 255
: 255
: 255
: 255
: $(( (255 << (8 - ( % 8))) & 255 )) # (255 << (8 - (18 % 8))) & 255 = 192
: 0
: 0
: 0
Let's examine the formulas used to set $1
and $6
a little closer. $1
is set to:
让我们来看看用来设置公式$1
和$6
一点点接近。$1
被设定为:
$(( 5 - ( / 8) ))
The maximum and minimum possible values for a CIDR prefix are 32 for netmask
对于网络掩码,CIDR 前缀的最大和最小可能值为 32
11111111.11111111.11111111.11111111
and 0 for netmask
和 0 为网络掩码
00000000.00000000.00000000.00000000
The above formula uses integer division, so the possible results range from 1 to 5:
上述公式使用整数除法,因此可能的结果范围为 1 到 5:
5 - (32 / 8) = 1
5 - ( 0 / 8) = 5
$6
is set to:
$6
被设定为:
$(( (255 << (8 - ( % 8))) & 255 ))
Let's break this down for our example CIDR prefix of 18
. First we take the modulus and do some subtraction:
让我们为我们的示例 CIDR 前缀18
. 首先我们取模数并做一些减法:
8 - (18 % 8) = 6
Next we bitwise shift 255 by this value:
接下来我们将 255 按此值进行位移:
255 << 6
This is the same as pushing six 0
bits onto the end of 255 in binary:
这与0
在二进制中将 6位推入 255 的末尾相同:
11111111000000
Finally, we bitwise AND this value with 255:
最后,我们将这个值与 255 按位与:
11111111000000 &
00000011111111 # 255
which gives
这使
00000011000000
or simply
或者干脆
11000000
Look familiar? This is the third octet in our netmask in binary:
看起来熟悉?这是二进制网络掩码中的第三个八位字节:
11111111.11111111.11000000.00000000
^------^
In decimal, the value is 192.
在十进制中,该值为 192。
Next we shift the positional parameters based on the value of $1
:
接下来,我们根据 的值移动位置参数$1
:
[ -gt 1 ] && shift || shift
In our case, the value of $1
is 3, so we shift the positional parameters 3 to the left. The previous value of $4
becomes the new value of $1
, the previous value of $5
becomes the value of $2
, and so on:
在我们的例子中,的值为$1
3,所以我们将位置参数 3 向左移动。的先前值$4
成为 的新值$1
, 的先前值$5
成为 的值$2
,依此类推:
: 255
: 255
: 192
: 0
: 0
: 0
These values should look familiar: they are the decimal octets from our netmask (with a couple of extra zeros tacked on at the end). To get the netmask, we simply print out the first four with dots in between them:
这些值应该看起来很熟悉:它们是来自我们网络掩码的十进制八位字节(在末尾附加几个额外的零)。要获得网络掩码,我们只需打印出前四个,中间有点:
echo ${1-0}.${2-0}.${3-0}.${4-0}
The -0
after each parameter says to use 0
as the default value if the parameter is not set.
-0
每个参数的after 表示0
如果未设置该参数,则用作默认值。
Output:
输出:
255.255.192.0