我从这个topic中找到了以下外壳函数
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转换为网络掩码,并将网络掩码转换为cidr?具体地说,对set、参数扩展${#…}和算术扩展$((…))的调用非常繁重。
发布于 2013-12-25 06:29:58
mask2cdr()
要从以点为十进制的网络掩码中获取CIDR前缀,请执行以下操作:
255.255.192.0首先必须将四个二进制八位数转换为二进制,然后计算最高有效位(即前导一的数量):
11111111.11111111.11000000.00000000 # 18 ones = /18 in CIDR这个函数相当有创意地做到了这一点。首先,我们去掉所有前导的255八位字节(即二进制中全部为1的八位字节),并将结果存储在变量x中
local x=${1##*255.}这一步使用了parameter expansion,整个脚本都非常依赖它。如果我们继续使用255.255.192.0的示例网络掩码,我们现在有以下值:
$1: 255.255.192.0
$x: 192.0接下来,我们设置三个变量:$1、$2和$3。这些变量称为positional parameters;它们非常类似于普通的命名变量,但通常是在将参数传递给脚本或函数时设置的。我们可以直接使用set --设置这些值,例如:
set -- foo bar # $1 = foo, $2 = bar我更喜欢使用命名变量而不是位置参数,因为它使脚本更容易阅读和调试,但最终结果是相同的。我们将$1设置为:
0^^^128^192^224^240^248^252^254^这实际上只是一个表,用于将特定的十进制值转换为二进制值,并计算1位数。我们稍后再来讨论这个问题。
我们将$2设置为
$(( (${#1} - ${#x})*2 ))这称为Arithmetic Expansion。它看起来很复杂,但它实际上只是计算我们在第一个命令中剥离的1位的数量。它分解为以下内容:
(number of chars in $1 - number of chars in $x) * 2在我们的例子中,计算结果是
(13 - 5) * 2 = 16我们去掉了两个二进制八位数所以我们得到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位。
现在我们只需要将前导的1位(总共16位,存储在变量$2中)和上一步的1位(总共2位)相加:
echo $(( $2 + (${#x}/4) ))哪里
${#x}/4是$x中的字符数除以4,即$x中四字符块的数量。
输出:
18cdr2mask()
让我们继续运行前面的示例,该示例的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让我们研究一下用于将$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 ))让我们以CIDR前缀18为例来分析这一点。首先,我们取模数并做一些减法:
8 - (18 % 8) = 6接下来,我们将按以下值按位移位255:
255 << 6这与将6个0位推入二进制255的末尾相同:
11111111000000最后,我们将此值与255进行逐位AND:
11111111000000 &
00000011111111 # 255这给了我们
00000011000000或者简单地说
11000000看起来眼熟吗?这是我们的网络掩码中的第三个二进制八位数:
11111111.11111111.11000000.00000000
^------^以十进制表示,该值为192。
接下来,我们根据$1的值移动位置参数
[ $1 -gt 1 ] && shift $1 || shift在我们的示例中,$1的值为3,因此我们将位置参数3向左移动。先前的$4值变为$1的新值,先前的$5值变为$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.0https://stackoverflow.com/questions/20762575
复制相似问题