【问题标题】:IP Address ConverterIP 地址转换器
【发布时间】:2012-05-26 16:54:01
【问题描述】:

有IP地址:66.102.13.19,并且从这个地址作为接收到这个地址

http://1113984275

但是怎么做呢?以及如何在 bash 的帮助下做到这一点。 比如this service可以,但是算法我不懂。

【问题讨论】:

    标签: bash ip converter


    【解决方案1】:

    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})
    

    【讨论】:

    • 这很好,但我们如何以另一种方式做到这一点。即 IP 号码 --> IP 地址
    • 我已经更新了如何将IP号码转换为IP地址的方法。 :)
    • 您可以通过指定记录分隔符来避免调用tr,即:awk 'BEGIN{RS="."}...awk '{s = s*256 + $1} END{print s}' RS=.
    【解决方案2】:
    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 脚本相同。

    【讨论】:

    • @AshBurlaczenko:给定 IP 地址的十进制数是 1113984275
    • 感谢您的决定,更清楚了,我更正了错误。以及如何进行逆运算?从1113984275得到66.102.13.19。
    • @ArmenB.:我不确定你在问什么,但是是的,通常可以在 shell 脚本中完成的任何事情都可以在命令行中完成,反之亦然。在某些例外或情况下,事情必须有所不同。在这种情况下,您可以在诸如~/bin/functions 之类的文件中包含函数(只是函数定义省略了shebang 和对函数的调用),并使用. $HOME/bin/functions 从您的~/.bashrc 中获取该函数(注意点)。然后你可以像这样从命令行调用函数:例如ip2dec 66.102.13.19
    • 如果您指的是 Bash 以外的其他 shell,那么可以,但如果另一个 shell 没有与此处使用的 Bash 相同的功能,则可能必须重写。
    • @Dennis:是的,其他 shell 我的意思是 sh 不是 bash。我正在寻找一种方法来做到这一点是香草壳。
    【解决方案3】:

    我认为有一个更简单的解决方案,它还可以处理任意数量的八位字节,而不引用固定偏移等。

    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)))的含义吗?
    • @yundongxu cat 命令读取通过管道传输到标准输入的数据,标准输入是一串二进制数字。表达式$((2#...)) 将“...”从基数 2 转换为十进制。
    【解决方案4】:

    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
    }
    

    【讨论】:

      【解决方案5】:

      二进制移位总是比乘法或除法快。
      使用二进制 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 清除变量 abcd 并防止八进制解释,您可以执行以下操作:((a=10#$a,b=10#$b,c=10#$c,d=10#$d))。请参阅:stackoverflow.com/questions/11123717/… 或者不要 declare -i 而是 echo "$(((10#$a&lt;&lt;24)+(10#$b&lt;&lt;16)+(10#$c&lt;&lt;8)+10#$d))";
      【解决方案6】:

      我的 int 到 ip 转换版本:

      echo 3232235521| awk {'print rshift(and($1, 0xFF000000), 24) "." rshift(and($1, 0x00FF0000), 16) "." rshift(and($1, 0x0000FF00), 8) "." and($1, 0x000000FF) '}

      【讨论】:

        【解决方案7】:

        这是我的看法:

        $ 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 可以是一个(bash)函数,如ip2d() { IFS=. eval 'set -- $1'; echo ...,d2ip 也可以写成IFS=\ read -r a b c d &lt; &lt;(echo "obase=256;$1" |bc)
        • 再短一点:A=($(dc -e "256o$1p"));IFS=. eval 'echo "${A[*]#0}"'(当四边形有两个前导 0 时,与原来的问题相同)。
        猜你喜欢
        • 1970-01-01
        • 2013-05-09
        • 1970-01-01
        • 2017-08-23
        • 2013-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多