IPv4アドレスと/ 24ネットワークのリストを含むファイルがあります。
IPアドレスはすでに一意で、4つのオクテットですべて整列しています。
bashを使用して同じ/ 24サブネットに属するアドレスをグループ化し(そのサブネットに複数のアドレスがある場合)、そうでない場合はIPアドレスをリストに保持したいと思います。
たとえば、
10.0.0.1
10.0.0.2
10.20.0.0/24
10.30.10.1
10.30.10.2
192.168.0.1
192.168.1.5
192.168.30.0/24
192.168.50.3
希望の出力:
10.0.0.0/24
10.20.0.0/24
10.30.10.0/24
192.168.0.1
192.168.1.5
192.168.30.0/24
192.168.50.3
答え1
基本的な考え方は、各/24
ネットワークをそのネットワークにサブネットアレイを格納するキーとして使用することです。次に、各配列の長さに基づいて出力を生成します。しかし、このアプローチには欠点があります。ストリーミングはサポートされていません。
参考としてのみ
AWK
awk '{
if (index($0, "/") > 0) { ip_map[$0] = "" }
else {
split($0, parts, ".")
network = parts[1]"."parts[2]"."parts[3]".0/24"
if (network in ip_map) { ip_map[network] = ip_map[network]" "$0 }
else { ip_map[network] = $0 }
}
}
END {
for (k in ip_map) {
if (ip_map[k] == "" || split(ip_map[k], arr) > 1) { print k }
else { print ip_map[k] }
}
}' | sort -n
強く打つ
#!/bin/bash
# or use `readarray -t` to read input from a file
ips=(
"10.0.0.1"
"10.0.0.2"
"10.0.0.3"
"10.20.0.0/24"
"10.30.10.1"
"10.30.10.2"
"192.168.0.1"
"192.168.1.5"
"192.168.30.0/24"
"192.168.50.3"
)
declare -A ip_map
for ip in "${ips[@]}"; do
if [[ "$ip" == *"/"* ]]; then
ip_map["$ip"]=null
else
network=$(echo "$ip" | { IFS="."; read a b c d; echo "$a.$b.$c.0/24"; })
if [[ ${ip_map[$network]+_} ]]; then
ip_map["$network"]+=" $ip"
else
ip_map["$network"]="$ip"
fi
fi
done
for k in "${!ip_map[@]}"; do
if [[ "${ip_map[$k]}" == null || $(echo "${ip_map[$k]}" | wc -w) -gt 1 ]]; then
echo "$k"
else
echo "${ip_map[$k]}"
fi
done | sort -n
Python
import ipaddress
ips = [
"10.0.0.1",
"10.0.0.2",
"10.0.0.3",
"10.20.0.0/24",
"10.30.10.1",
"10.30.10.2",
"192.168.0.1",
"192.168.1.5",
"192.168.30.0/24",
"192.168.50.3",
]
ip_map = {}
for ip in ips:
if "/" in ip:
ip_map[ip] = None
else:
network = ipaddress.ip_network(ip + "/24", strict=False)
try:
ip_map[network].append(ip)
except KeyError:
ip_map[network] = [ip]
for k, v in ip_map.items():
if v is None or len(v) > 1:
print(k)
elif len(v) == 1:
print(v[0])