问题
在测试软件的工作中,时不时需要以ip地址作为程序的输入数据,比如给网络设备批量下发以ip为关键参数的配置、模拟大量客户端ip对某服务端程序进行压力测试。 那么如何用shell脚本生成一定数量的随机且不重复的ip地址呢?
回答
为了简化脚本实现,我们可以将ip地址限定在给定的网段内,子网掩码长度可以用参数指定。 我们可以使用 ipcalc 命令计算子网内可用的ip地址范围,这个ip范围可以看成一个元素为ip的数组;使用 shuf 命令生成随机且不重复的整数序列,这些整数可以看成是数组的索引;这样结合起来便可实现问题需求。 经过笔者编写调测后,给出代码如下:
代码语言:javascript复制#! /bin/bash
# 将正整数转换为 ip 地址
convert_num_to_ip() {
local num=$1
b1=$(( num >> 24))
b2=$(( (num & 0x00ffffff) >> 16))
b3=$(( (num & 0x0000ffff) >> 8))
b4=$(( num & 0x000000ff ))
local ip="${b1}.${b2}.${b3}.${b4}"
echo $ip
}
# 将 ip 地址转换为正整数
convert_ip_to_num() {
local ip=$1
IFS='.' read -ra bytes <<< "$ip"
local num=$(( (${bytes[0]} << 24) (${bytes[1]} << 16) (${bytes[2]} << 8) ${bytes[3]} ))
echo $num
}
# 检查脚本参数数量
if [ "$#" -ne 3 ]; then
echo "Usage: $0 <ip_address> <mask_len> <number_of_ips>"
exit 1
fi
ip_address=$1
mask_len=$2
num_ips=$3
if [ "$mask_len" -lt 8 ] || [ "$mask_len" -gt 30 ]; then
echo "Subnet mask length must be between 8 and 30."
exit 1
fi
calc_result=$(ipcalc -n -b "$ip_address/$mask_len")
# 获取网络内第一个可用IP地址
first_ip=$(echo "$calc_result" | grep HostMin | awk '{print $2}')
# 获取网络内最后一个可用IP地址
last_ip=$(echo "$calc_result" | grep HostMax | awk '{print $2}')
min_ip=$(convert_ip_to_num $first_ip)
max_ip=$(convert_ip_to_num $last_ip)
max_range=$(( max_ip - min_ip ))
# 生成随机且不重复的整数序列
idxs=$(shuf -i 0-${max_range} -n ${num_ips})
# 输出所有生成的 IP 地址
for idx in $idxs; do
ip=$((min_ip idx))
convert_num_to_ip $ip
done
我们可以测试一下:
在使用 shuf 命令之前,有一版本的代码生成的 ip 中会出现重复的,为了验证现在这版代码是否会生成重复 ip,我们可以做如下测试:
参考
- man ipcalc
- man shuf