17

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

4

7 回答 7

44

使用按位&( 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
于 2013-03-15T10:18:11.623 回答
14

一些 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))
}
于 2015-09-21T08:35:16.957 回答
9

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

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)))"
于 2015-07-24T15:20:37.770 回答
3

对于在谷歌搜索时遇到此问题并需要在 BusyBox 中以及因此在许多路由器上有效的答案的人来说,这里有一些适合这种情况的东西ashsh

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
于 2020-11-17T15:00:45.650 回答
1

很好的答案,尽管上面的答案中有轻微的错字。

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

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

于 2014-08-25T21:34:38.743 回答
0

除了@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}))
于 2016-02-18T22:01:27.270 回答
0

基于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
于 2021-07-14T18:16:20.417 回答