这不是最简单的方法,但是您可以执行以下操作:
$ 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}运营商来自),bash4.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"