【发布时间】:2012-05-26 16:54:01
【问题描述】:
有IP地址:66.102.13.19,并且从这个地址作为接收到这个地址
http://1113984275
但是怎么做呢?以及如何在 bash 的帮助下做到这一点。 比如this service可以,但是算法我不懂。
【问题讨论】:
有IP地址:66.102.13.19,并且从这个地址作为接收到这个地址
http://1113984275
但是怎么做呢?以及如何在 bash 的帮助下做到这一点。 比如this service可以,但是算法我不懂。
【问题讨论】:
IP地址->号码:
echo 66.102.13.19 | tr . '\n' | awk '{s = s*256 + $1} END{print s}'
编号 -> IP 地址:
(export ip=1113984275; for i in {1..4}; do s='.'$((ip%256))$s && ((ip>>=8)); done; echo ${s:1})
【讨论】:
tr,即:awk 'BEGIN{RS="."}...或awk '{s = s*256 + $1} END{print s}' RS=.
ip=66.102.13.19
IFS=. read -r a b c d <<< "$ip"
printf '%s%d\n' "http://" "$((a * 256 ** 3 + b * 256 ** 2 + c * 256 + d))"
顺便说一下,您问题中的数字与 IP 地址不匹配。
将小数转换为 IP:
#!/bin/bash
dec2ip () {
local ip dec=$@
for e in {3..0}
do
((octet = dec / (256 ** e) ))
((dec -= octet * 256 ** e))
ip+=$delim$octet
delim=.
done
printf '%s\n' "$ip"
}
dec2ip "$@"
将 IP 转换为小数:
#!/bin/bash
ip2dec () {
local a b c d ip=$@
IFS=. read -r a b c d <<< "$ip"
printf '%d\n' "$((a * 256 ** 3 + b * 256 ** 2 + c * 256 + d))"
}
ip2dec "$@"
演示:
$ ./dec2ip 1113984275
66.102.13.19
$ ./ip2dec 66.102.13.19
1113984275
这两个脚本依赖于一些 Bourne 衍生的 shell 中不存在的 Bash 功能。以下是可供使用的 AWK 版本:
#!/usr/bin/awk -f
# dec2ip
BEGIN {
dec = ARGV[1]
for (e = 3; e >= 0; e--) {
octet = int(dec / (256 ^ e))
dec -= octet * 256 ^ e
ip = ip delim octet
delim = "."
}
printf("%s\n", ip)
}
和
#!/usr/bin/awk -f
# ip2dec
BEGIN {
ip = ARGV[1]
split(ip, octets, ".")
for (i = 1; i <= 4; i++) {
dec += octets[i] * 256 ** (4 - i)
}
printf("%i\n", dec)
}
它们的调用方式与上面的 Bash 脚本相同。
【讨论】:
~/bin/functions 之类的文件中包含函数(只是函数定义省略了shebang 和对函数的调用),并使用. $HOME/bin/functions 从您的~/.bashrc 中获取该函数(注意点)。然后你可以像这样从命令行调用函数:例如ip2dec 66.102.13.19。
sh 不是 bash。我正在寻找一种方法来做到这一点是香草壳。
我认为有一个更简单的解决方案,它还可以处理任意数量的八位字节,而不引用固定偏移等。
echo 66.102.13.19 |
tr . '\n' |
while read octet; do
printf "%.08d" $(echo "obase=2;$octet" | bc)
done |
echo $((2#$(cat)))
输出:1113984275
【讨论】:
$((2#$(cat)))的含义吗?
cat 命令读取通过管道传输到标准输入的数据,标准输入是一串二进制数字。表达式$((2#...)) 将“...”从基数 2 转换为十进制。
bash 的简单 int 到 IP 转换
dec2ip ()
{
local v=$1
local i1=$((v>>24&255))
local i2=$((v>>16&255))
local i3=$((v>>8&255))
local i4=$((v&255))
printf '%d.%d.%d.%d\n' $i1 $i2 $i3 $i4
}
【讨论】:
二进制移位总是比乘法或除法快。
使用二进制 AND 比 mod 更快。
ip2dec(){ # Convert an IPv4 IP number to its decimal equivalent.
declare -i a b c d;
IFS=. read a b c d <<<"$*";
echo "$(((a<<24)+(b<<16)+(c<<8)+d))";
}
dec2ip(){ # Convert an IPv4 decimal IP value to an IPv4 IP.
declare -i a=$((0xff)) b=$1;
c="$((b>>24&a)).$((b>>16&a)).$((b>>8&a)).$((b&a))";
echo "$c";
}
ip=66.102.13.19
a=$(ip2dec "$ip")
b=$(dec2ip "$a")
echo "$ip DecIP=$a IPv4=$b "
注意:此系统将失败,并显示 0008 之类的值。
Bash 认为它是一个八进制数。
为了解决这个问题,每个值都必须使用以下内容进行清理:
IsDecInt()( # Is the value given on $1 a decimal integer (with sign)?
declare n=$1; set --
if [[ $n =~ ^([+-]?)((0)|0*([0-9]*))$ ]]; then
set -- "${BASH_REMATCH[@]:1}"
else
exit 1
fi
echo "$1$3$4";
)
a=$(IsDecInt "$a")||{ Echo "Value $a is not an integer" >&2; exit 1; }
对于(非常)旧的 shell:从 2.04 开始的 bash,或 dash 或任何(合理的)shell:
ip2dec(){ # Convert an IPv4 IP number to its decimal equivalent.
local a b c d;
IFS=. read a b c d <<-_EOF_
$1
_EOF_
echo "$(((a<<24)+(b<<16)+(c<<8)+d))";
}
dec2ip(){ # Convert an IPv4 decimal IP value to an IPv4 IP.
local a=$((~(-1<<8))) b=$1;
c="$((b>>24&a)).$((b>>16&a)).$((b>>8&a)).$((b&a))";
echo "$c";
}
ip=$1
a=$(ip2dec "$ip")
b=$(dec2ip "$a")
echo "$ip DecIP=$a IPv4=$b "
【讨论】:
0 清除变量 a、b、c 和 d 并防止八进制解释,您可以执行以下操作:((a=10#$a,b=10#$b,c=10#$c,d=10#$d))。请参阅:stackoverflow.com/questions/11123717/… 或者不要 declare -i 而是 echo "$(((10#$a<<24)+(10#$b<<16)+(10#$c<<8)+10#$d))";
我的 int 到 ip 转换版本:
echo 3232235521| awk {'print rshift(and($1, 0xFF000000), 24) "." rshift(and($1, 0x00FF0000), 16) "." rshift(and($1, 0x0000FF00), 8) "." and($1, 0x000000FF) '}
【讨论】:
这是我的看法:
$ host google.com
google.com has address 216.58.216.142
$ ./ip2d.sh 216.58.216.142
3627735182
$ ./d2ip.sh 3627735182
216.58.216.142
ip2d.sh:
#!/bin/bash
IFS=.
set -- $*
echo $(( ($1*256**3) + ($2*256**2) + ($3*256) + ($4) ))
d2ip.sh:
#!/bin/bash
IFS=" " read -r a b c d <<< $(echo "obase=256 ; $1" |bc)
echo ${a#0}.${b#0}.${c#0}.${d#0}
【讨论】:
ip2d() { IFS=. eval 'set -- $1'; echo ...,d2ip 也可以写成IFS=\ read -r a b c d < <(echo "obase=256;$1" |bc)
A=($(dc -e "256o$1p"));IFS=. eval 'echo "${A[*]#0}"'(当四边形有两个前导 0 时,与原来的问题相同)。