【问题标题】:Given the IP and netmask, how can I calculate the network address using bash?给定 IP 和网络掩码,如何使用 bash 计算网络地址?
【发布时间】:2013-03-03 23:47:30
【问题描述】:

在 bash 脚本中,我有一个类似 192.168.1.15 的 IP 地址和一个类似 255.255.0.0 的网络掩码。我现在想计算这个网络的起始地址,这意味着在两个地址上都使用 & 运算符。在示例中,结果将为 192.168.0.0。有人准备好这样的东西吗?我正在寻找一种优雅的方式来处理来自 bash 的 IP 地址

【问题讨论】:

  • 你可以考虑ipcalc
  • ipcalc 是一个可以下载的 perl cgi 脚本。谢谢,对于任何想要在 PERL 中实现它的人来说,这都是一个很好的来源。我一直在寻找 bash 中的解决方案,但 perl 也可以在 shell 脚本中工作。
  • 不,我的意思是 ipcalc 的 unix 命令行。请参阅answers.oreilly.com/topic/… 了解更多信息。作为替代方案,您也可以使用支持 IPv6 的 sipcalc(也是一个 cli 工具)
  • 如果我有代表,我会将此作为评论添加... cevings 答案的用法... # 用法:网络掩码 #bits # 例如。网络掩码 24 => 255.255.255.0 # 用法:广播地址掩码 # 例如。广播 192.168.0.1 24 => 192.168.0.255 # 用法:网络地址掩码 # 例如。网络 192.168.0.123 24 => 192.168.0.0

标签: bash ip subnet netmask


【解决方案1】:

使用按位& (AND) 运算符:

$ IFS=. read -r i1 i2 i3 i4 <<< "192.168.1.15"
$ IFS=. read -r m1 m2 m3 m4 <<< "255.255.0.0"
$ printf "%d.%d.%d.%d\n" "$((i1 & m1))" "$((i2 & m2))" "$((i3 & m3))" "$((i4 & m4))"
192.168.0.0

以另一个 IP 和掩码为例:

$ IFS=. read -r i1 i2 i3 i4 <<< "10.0.14.97"
$ IFS=. read -r m1 m2 m3 m4 <<< "255.255.255.248"
$ printf "%d.%d.%d.%d\n" "$((i1 & m1))" "$((i2 & m2))" "$((i3 & m3))" "$((i4 & m4))"
10.0.14.96

【讨论】:

  • 非常感谢!正是我想要的,漂亮!
  • 这太棒了。感谢您花时间开发它。
【解决方案2】:

一些总结所有其他答案的 Bash 函数。

ip2int()
{
    local a b c d
    { IFS=. read a b c d; } <<< $1
    echo $(((((((a << 8) | b) << 8) | c) << 8) | d))
}

int2ip()
{
    local ui32=$1; shift
    local ip n
    for n in 1 2 3 4; do
        ip=$((ui32 & 0xff))${ip:+.}$ip
        ui32=$((ui32 >> 8))
    done
    echo $ip
}

netmask()
# Example: netmask 24 => 255.255.255.0
{
    local mask=$((0xffffffff << (32 - $1))); shift
    int2ip $mask
}


broadcast()
# Example: broadcast 192.0.2.0 24 => 192.0.2.255
{
    local addr=$(ip2int $1); shift
    local mask=$((0xffffffff << (32 -$1))); shift
    int2ip $((addr | ~mask))
}

network()
# Example: network 192.0.2.0 24 => 192.0.2.0
{
    local addr=$(ip2int $1); shift
    local mask=$((0xffffffff << (32 -$1))); shift
    int2ip $((addr & mask))
}

【讨论】:

  • 很好,但是一个示例行可以为我节省 15 分钟的时间来确定您的参数期望。“network 192.168.8.1 31”或“netmask 16”
  • 就这样吧,回到原来的样子。
  • 在广播和网络函数中有两个参数。 32 - $1 不应该是 32 - $2 吗?我添加了将 cidr 表示法与 [ $# -eq 1 ] &amp;&amp; echo "$1" | grep -E '[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/[0-9]{1,2}' &amp;&amp; IFS=/ read -ra cidr &lt;&lt;&lt; "$1" 之类的东西一起使用的可能性,以便能够将其与 ip -o -f inet addr show dev enp3s0 | awk '/scope global/ {print $4}' 的输出一起使用
  • @badc0de shift 的调用使$2 变为$1
  • 啊!我错过了。我有自己的脚本版本,为了清楚起见,我必须在某些时候更改它。无论如何感谢您的回答和代码
【解决方案3】:

如果您只有可用的网络前缀(没有网络掩码),只需添加一个替代方案:

IP=10.20.30.240
PREFIX=26
IFS=. read -r i1 i2 i3 i4 <<< $IP
IFS=. read -r xx m1 m2 m3 m4 <<< $(for a in $(seq 1 32); do if [ $(((a - 1) % 8)) -eq 0 ]; then echo -n .; fi; if [ $a -le $PREFIX ]; then echo -n 1; else echo -n 0; fi; done)
printf "%d.%d.%d.%d\n" "$((i1 & (2#$m1)))" "$((i2 & (2#$m2)))" "$((i3 & (2#$m3)))" "$((i4 & (2#$m4)))"

【讨论】:

    【解决方案4】:

    对于那些在谷歌搜索时遇到此问题并需要在 ash 中工作的答案的人,sh 包含在 BusyBox 中,因此在许多路由器上,这里有一些适合这种情况的东西:

    IP=10.20.30.240
    MASK=255.255.252.0
    IFS=. read -r i1 i2 i3 i4 << EOF
    $IP
    EOF
    IFS=. read -r m1 m2 m3 m4 << EOF
    $MASK
    EOF
    read masked << EOF
    $(( $i1 & $m1 )).$(( $i2 & $m2 )).$(( $i3 & $m3 )).$(( $i4 & $m4 ))
    EOF
    echo $masked
    

    如果您只有前缀长度,请执行以下操作:

    IP=10.20.30.240
    PREFIX=22
    IFS=. read -r i1 i2 i3 i4 << EOF
    $IP
    EOF
    mask=$(( ((1<<32)-1) & (((1<<32)-1) << (32 - $PREFIX)) ))
    read masked << EOF
    $(( $i1 & ($mask>>24) )).$(( $i2 & ($mask>>16) )).$(( $i3 & ($mask>>8) )).$(( $i4 & $mask ))
    EOF
    echo $masked
    

    【讨论】:

      【解决方案5】:

      很好的答案,虽然上面的答案有小错误。

      $ printf "%d.%d.%d.%d\n" "$((i1 & m1))" "$(($i2  <-- $i2 should be i2
      

      如果有人知道如何计算广播地址(XOR 网络),然后计算网络和广播之间的可用节点,我会对接下来的步骤感兴趣。我必须在 /23 内的列表中查找地址。

      【讨论】:

      • 上面哪个答案?有几个
      【解决方案6】:

      除了@Janci 的回答

      IP=10.20.30.240
      PREFIX=26
      IFS=. read -r i1 i2 i3 i4 <<< $IP
      D2B=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1})
      binIP=${D2B[$i1]}${D2B[$i2]}${D2B[$i3]}${D2B[$i4]}
      binIP0=${binIP::$PREFIX}$(printf '0%.0s' $(seq 1 $((32-$PREFIX))))
      # binIP1=${binIP::$PREFIX}$(printf '0%.0s' $(seq 1 $((31-$PREFIX))))1
      echo $((2#${binIP0::8})).$((2#${binIP0:8:8})).$((2#${binIP0:16:8})).$((2#${binIP0:24:8}))
      

      【讨论】:

        【解决方案7】:

        基于https://stackoverflow.com/a/64877749/2716218我尝试简化并想出了

        IP=10.20.30.240
        PREFIX=22
        IFS=. read -r i1 i2 i3 i4 <<< $IP
        mask=$(( ((1<<32)-1) & (((1<<32)-1) << (32 - $PREFIX)) ))
        masked=$(( $i1 & ($mask>>24) )).$(( $i2 & ($mask>>16) )).$(( $i3 & ($mask>>8) )).$(( $i4 & $mask ))
        echo $masked
        

        【讨论】:

          猜你喜欢
          • 2017-10-08
          • 2010-12-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多