如何生成指定数量的 随机且不重复的 ip地址

2024-09-10 20:31:26 浏览数 (2)

问题

在测试软件的工作中,时不时需要以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

0 人点赞