这不是最简单的方法,但是您可以执行以下操作:
$ IP=109.96.77.15
$ echo "$((${-+"(${IP//./"+256*("}))))"}&255))"
109
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>8&255))"
96
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>16&255))"
77
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>24&255))"
15
这应该在ksh93的工作(如该${var//pattern/replacement}
运营商来自),bash
4.3以上,busybox的sh
,yash
,mksh
和zsh
,但当然在zsh
,有更简单的方法。在的旧版本中bash
,您需要删除内引号。它也适用于在大多数其他shell中删除的那些内引号,但不适用于ksh93。
假定$IP
包含一个有效的IPv4地址的四进制表示形式(尽管它也适用于类似四进制的表示形式0x6d.0x60.0x4d.0xf
(在某些shell中甚至是八进制的表示形式,但将以十进制形式输出值)。如果的内容$IP
来自不受信任的来源,则将构成命令注入漏洞。
基本上,当我们用替换每个.
in $IP
时+256*(
,我们最终进行评估:
$(( (109+256*(96+256*(77+256*(15))))>> x &255 ))
因此,我们构建了这4个字节像IPv4地址的32位整数最终是(虽然与字节逆转)¹,然后使用>>
,&
位运算符来提取相关的字节。
我们使用${param+value}
标准运算符($-
保证始终在此处设置),而不是仅仅value
因为否则算术解析器会抱怨括号不匹配。此处的壳可以找到))
开口的闭合$((
,然后在内部进行膨胀,这将导致算术表达式求值。
随着$(((${IP//./"+256*("}))))&255))
相反,外壳会认为第二和第三)
有S作为结束))
的$((
,并报告语法错误。
在ksh93中,您还可以执行以下操作:
$ echo "${IP/@(*).@(*).@(*).@(*)/\2}"
96
bash
,mksh
,zsh
已复制ksh93的的${var/pattern/replacement}
运营商,但不是捕获组处理的一部分。zsh
用不同的语法支持它:
$ setopt extendedglob # for (#b)
$ echo ${IP/(#b)(*).(*).(*).(*)/$match[2]}'
96
bash
确实在其regexp匹配运算符中支持某种形式的捕获组处理,但在${var/pattern/replacement}
。
POSIXly,您将使用:
(IFS=.; set -o noglob; set -- $IP; printf '%s\n' "$2")
该noglob
避免坏的惊喜的价值观$IP
一样10.*.*.*
,子shell来限制这些更改选项和范围$IFS
。
¹IPv4地址仅为32位整数,例如127.0.0.1只是许多(尽管是最常见的)文本表示形式之一。环回接口的相同的典型IPv4地址也可以表示为0x7f000001或127.1(也许更合适的说法1
是127.0 / 8 A类网络上的地址)或0177.0.1,或其他1的组合最多4个数字,以八进制,十进制或十六进制表示。您可以将所有这些传递ping
给例如,然后您将看到它们将对localhost进行ping操作。
如果您不介意$n
在bash
或ksh93
或zsh -o octalzeroes
或中设置任意临时变量(在此处)的副作用lksh -o posix
,则可以使用以下命令将所有这些表示形式简单地转换回32位整数:
$((n=32,(${IP//./"<<(n-=8))+("})))
然后使用上述>>
/ &
组合提取所有组件。
$ IP=0x7f000001
$ echo "$((n=32,(${IP//./"<<(n-=8))+("})))"
2130706433
$ IP=127.1
$ echo "$((n=32,(${IP//./"<<(n-=8))+("})))"
2130706433
$ echo "$((n=32,((${IP//./"<<(n-=8))+("}))>>24&255))"
127
$ perl -MSocket -le 'print unpack("L>", inet_aton("127.0.0.1"))'
2130706433
mksh
对它的算术表达式使用带符号的32位整数,可以$((# n=32,...))
在其中强制使用无符号的32位数字(以及posix
用于识别八进制常量的选项)。
IFS
在read
那里设置:IFS=. read -a ArrIP<<<"$IP"