Bash 脚本以列出前缀中的所有 IP
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16986879/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash script to list all IPs in prefix
提问by user2463938
I'm trying to create script that I can input a set of prefixes, which will then list all IP addresses within the prefixes (including network/host/broadcast).
我正在尝试创建可以输入一组前缀的脚本,然后将列出前缀中的所有 IP 地址(包括网络/主机/广播)。
An example would be:
一个例子是:
./convert-prefix-to-IPs.sh 192.168.0.0/23 203.20.0.0/16
192.168.0.0
192.168.0.1
...
192.168.0.255
192.168.1.0
..
192.168.1.255
203.20.0.0
..
203.20.255.255
There are some python/perl scripts which can do this, but I'm hoping to have a simple bash script, as it may be used on systems without perl/python (yes.. i know.. )
有一些 python/perl 脚本可以做到这一点,但我希望有一个简单的 bash 脚本,因为它可以在没有 perl/python 的系统上使用(是的..我知道..)
回答by John Vossler
Here is what I use to generate all the IP addresses in a given CIDR block
这是我用来在给定 CIDR 块中生成所有 IP 地址的内容
nmap -sL 10.10.64.0/27 | awk '/Nmap scan report/{print $NF}'
Just that simple
就这么简单
The above command outputs this
上面的命令输出这个
10.10.64.0
10.10.64.1
10.10.64.2
10.10.64.3
10.10.64.4
10.10.64.5
10.10.64.6
10.10.64.7
10.10.64.8
10.10.64.9
10.10.64.10
10.10.64.11
10.10.64.12
10.10.64.13
10.10.64.14
10.10.64.15
10.10.64.16
10.10.64.17
10.10.64.18
10.10.64.19
10.10.64.20
10.10.64.21
10.10.64.22
10.10.64.23
10.10.64.24
10.10.64.25
10.10.64.26
10.10.64.27
10.10.64.28
10.10.64.29
10.10.64.30
10.10.64.31
回答by Kyoungs
I too was looking for this solution and found that @scherand script worked great. I also have added to this script to give you more option. Help File below.
我也在寻找这个解决方案,发现 @scherand 脚本工作得很好。我还添加到此脚本中,为您提供更多选择。下面的帮助文件。
THIS SCRIPT WILL EXPAND A CIDRADDRESS.
此脚本将扩展CIDR地址。
SYNOPSIS
概要
./cidr-to-ip.sh [OPTION(only one)] [STRING/FILENAME]
DESCRIPTION
描述
-h Displays this help screen
-f Forces a check for network boundary when given a STRING(s)
-i Will read from an Input file (file should contain one CIDR per line) (no network boundary check)
-b Will do the same as –i but with network boundary check
-h 显示此帮助屏幕
-f 在给定 STRING(s) 时强制检查网络边界
-i 将从输入文件中读取(文件每行应包含一个 CIDR)(无网络边界检查)
-b 与 -i 相同,但具有网络边界检查
EXAMPLES
例子
./cidr-to-ip.sh 192.168.0.1/24
./cidr-to-ip.sh 192.168.0.1/24 10.10.0.0/28
./cidr-to-ip.sh -f 192.168.0.0/16
./cidr-to-ip.sh -i inputfile.txt
./cidr-to-ip.sh -b inputfile.txt
./cidr-to-ip.sh 192.168.0.1/24
./cidr-to-ip.sh 192.168.0.1/24 10.10.0.0/28
./cidr-to-ip.sh -f 192.168.0.0/16
./cidr-to-ip.sh -i inputfile.txt
./cidr-to-ip.sh -b inputfile.txt
#!/bin/bash
############################
## Methods
############################
prefix_to_bit_netmask() {
prefix=;
shift=$(( 32 - prefix ));
bitmask=""
for (( i=0; i < 32; i++ )); do
num=0
if [ $i -lt $prefix ]; then
num=1
fi
space=
if [ $(( i % 8 )) -eq 0 ]; then
space=" ";
fi
bitmask="${bitmask}${space}${num}"
done
echo $bitmask
}
bit_netmask_to_wildcard_netmask() {
bitmask=;
wildcard_mask=
for octet in $bitmask; do
wildcard_mask="${wildcard_mask} $(( 255 - 2#$octet ))"
done
echo $wildcard_mask;
}
check_net_boundary() {
net=;
wildcard_mask=;
is_correct=1;
for (( i = 1; i <= 4; i++ )); do
net_octet=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
if [ $(( $net_octet&$mask_octet )) -ne 0 ]; then
is_correct=0;
fi
fi
done
echo $is_correct;
}
#######################
## MAIN
#######################
OPTIND=1;
getopts "fibh" force;
shift $((OPTIND-1))
if [ $force = 'h' ]; then
echo ""
echo -e "THIS SCRIPT WILL EXPAND A CIDR ADDRESS.\n\nSYNOPSIS\n ./cidr-to-ip.sh [OPTION(only one)] [STRING/FILENAME]\nDESCRIPTION\n -h Displays this help screen\n -f Forces a check for network boundary when given a STRING(s)\n -i Will read from an Input file (no network boundary check)\n -b Will do the same as –i but with network boundary check\n\nEXAMPLES\n ./cidr-to-ip.sh 192.168.0.1/24\n ./cidr-to-ip.sh 192.168.0.1/24 10.10.0.0/28\n ./cidr-to-ip.sh -f 192.168.0.0/16\n ./cidr-to-ip.sh -i inputfile.txt\n ./cidr-to-ip.sh -b inputfile.txt\n"
exit
fi
if [ $force = 'i' ] || [ $force = 'b' ]; then
old_IPS=$IPS
IPS=$'\n'
lines=($(cat )) # array
IPS=$old_IPS
else
lines=$@
fi
for ip in ${lines[@]}; do
net=$(echo $ip | cut -d '/' -f 1);
prefix=$(echo $ip | cut -d '/' -f 2);
do_processing=1;
bit_netmask=$(prefix_to_bit_netmask $prefix);
wildcard_mask=$(bit_netmask_to_wildcard_netmask "$bit_netmask");
is_net_boundary=$(check_net_boundary $net "$wildcard_mask");
if [ $force = 'f' ] && [ $is_net_boundary -ne 1 ] || [ $force = 'b' ] && [ $is_net_boundary -ne 1 ] ; then
read -p "Not a network boundary! Continue anyway (y/N)? " -n 1 -r
echo ## move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_processing=1;
else
do_processing=0;
fi
fi
if [ $do_processing -eq 1 ]; then
str=
for (( i = 1; i <= 4; i++ )); do
range=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
range="{$range..$(( $range | $mask_octet ))}";
fi
str="${str} $range"
done
ips=$(echo $str | sed "s, ,\.,g"); ## replace spaces with periods, a join...
eval echo $ips | tr ' ' '\n'
else
exit
fi
done
回答by Alex Harvey
This short script will print all the IP addresses in a CIDR range in a few lines of Bash. (I named it prips
after the Ubuntu command of the same name. Obviously, if that command is available, use that.)
这个简短的脚本将在几行 Bash 中打印出 CIDR 范围内的所有 IP 地址。(我以同名prips
的Ubuntu 命令命名它。显然,如果该命令可用,请使用它。)
prips() {
local cidr= ; local lo hi a b c d e f g h
# range is bounded by network (-n) & broadcast (-b) addresses.
lo=$(ipcalc -n "$cidr" | cut -f2 -d=)
hi=$(ipcalc -b "$cidr" | cut -f2 -d=)
IFS=. read -r a b c d <<< "$lo"
IFS=. read -r e f g h <<< "$hi"
eval "echo {$a..$e}.{$b..$f}.{$c..$g}.{$d..$h}"
}
Note that I assume the RedHat Linux (Erik Troan, Preston Brown) version of ipcalc
, not the Krischan Jodies version that is installed on some platforms (e.g. Mac OS X).
请注意,我假设的是 RedHat Linux(Erik Troan、Preston Brown)版本ipcalc
,而不是安装在某些平台(例如 Mac OS X)上的 Krischan Jodies 版本。
Examples:
例子:
$ prips 10.0.0.128/27
10.0.0.128 10.0.0.129 10.0.0.130 10.0.0.131 10.0.0.132 10.0.0.133 10.0.0.134 10.0.0.135 10.0.0.136 10.0.0.137 10.0.0.138 10.0.0.139 10.0.0.140 10.0.0.141 10.0.0.142 10.0.0.143 10.0.0.144 10.0.0.145 10.0.0.146 10.0.0.147 10.0.0.148 10.0.0.149 10.0.0.150 10.0.0.151 10.0.0.152 10.0.0.153 10.0.0.154 10.0.0.155 10.0.0.156 10.0.0.157 10.0.0.158 10.0.0.159
Calculates correct number of addresses in a /23 networks:
计算 /23 网络中正确的地址数:
$ prips 10.0.0.0/23 | wc -w
512
Inspecting a few of those addresses using cut:
使用 cut 检查其中一些地址:
$ prips 10.0.0.0/23 | cut -f1-10,256-266 -d' '
10.0.0.0 10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4 10.0.0.5 10.0.0.6 10.0.0.7 10.0.0.8 10.0.0.9 10.0.0.255 10.0.1.0 10.0.1.1 10.0.1.2 10.0.1.3 10.0.1.4 10.0.1.5 10.0.1.6 10.0.1.7 10.0.1.8 10.0.1.9
And maybe too slow but also correctly generates the 16 million addresses in a /8 network:
也许太慢了,但也能在 /8 网络中正确生成 1600 万个地址:
$ date ; prips 10.0.0.0/8 | wc -w ; date
Sat May 20 18:06:00 AEST 2017
16777216
Sat May 20 18:06:41 AEST 2017
回答by Jakub Bochenski
nmap
is useful, but an overkill.
nmap
很有用,但有点矫枉过正。
You can use prips
instead. Saves you the hassle of grepping out the extra output from nmap
and using awk
.
你可以prips
改用。节省你grepping出额外输出的麻烦nmap
和使用awk
。
Calling prips 192.168.0.0/23
will print what you need.
调用prips 192.168.0.0/23
将打印您需要的内容。
I use the following to skip the network address and broadcast: prips "$subnet" | sed -e '1d; $d'
我使用以下内容跳过网络地址和广播: prips "$subnet" | sed -e '1d; $d'
Prips also has other useful options, e.g. being able to sample every n-th IP.
Prips 还具有其他有用的选项,例如能够对每个第 n 个 IP 进行采样。
It's available via apt
,brew
,rpm
and as tar.gz
.
这是通过使用apt
,brew
,rpm
和tar.gz
。
回答by Florian Feldhaus
I recently wrote a function to generate all IP addresses from a given network address. The function takes the network address as argument and accepts CIDR and subnet masks. The script then stores all IPs in the array variable $ips.
我最近编写了一个函数来从给定的网络地址生成所有 IP 地址。该函数将网络地址作为参数并接受 CIDR 和子网掩码。然后脚本将所有 IP 存储在数组变量 $ips 中。
Code
代码
function network_address_to_ips() {
# define empty array to hold the ip addresses
ips=()
# create array containing network address and subnet
network=(${1//\// })
# split network address by dot
iparr=(${network[0]//./ })
# check for subnet mask or create subnet mask from CIDR notation
if [[ ${network[1]} =~ '.' ]]; then
netmaskarr=(${network[1]//./ })
else
if [[ $((8-${network[1]})) -gt 0 ]]; then
netmaskarr=($((256-2**(8-${network[1]}))) 0 0 0)
elif [[ $((16-${network[1]})) -gt 0 ]]; then
netmaskarr=(255 $((256-2**(16-${network[1]}))) 0 0)
elif [[ $((24-${network[1]})) -gt 0 ]]; then
netmaskarr=(255 255 $((256-2**(24-${network[1]}))) 0)
elif [[ $((32-${network[1]})) -gt 0 ]]; then
netmaskarr=(255 255 255 $((256-2**(32-${network[1]}))))
fi
fi
# correct wrong subnet masks (e.g. 240.192.255.0 to 255.255.255.0)
[[ ${netmaskarr[2]} == 255 ]] && netmaskarr[1]=255
[[ ${netmaskarr[1]} == 255 ]] && netmaskarr[0]=255
# generate list of ip addresses
for i in $(seq 0 $((255-${netmaskarr[0]}))); do
for j in $(seq 0 $((255-${netmaskarr[1]}))); do
for k in $(seq 0 $((255-${netmaskarr[2]}))); do
for l in $(seq 1 $((255-${netmaskarr[3]}))); do
ips+=( $(( $i+$(( ${iparr[0]} & ${netmaskarr[0]})) ))"."$(( $j+$(( ${iparr[1]} & ${netmaskarr[1]})) ))"."$(($k+$(( ${iparr[2]} & ${netmaskarr[2]})) ))"."$(($l+$((${iparr[3]} & ${netmaskarr[3]})) )) )
done
done
done
done
}
Example
例子
network_address_to_ips 10.0.1.0/255.255.255.240
echo ${ips[@]}
network_address_to_ips 10.1.0.0/24
echo ${ips[@]}
回答by rberg
I think this little script I hacked together does the trick. If not, it's definitely a starting point! Good luck.
我认为我一起编写的这个小脚本可以解决问题。如果没有,这绝对是一个起点!祝你好运。
#!/bin/bash
############################
## Methods
############################
prefix_to_bit_netmask() {
prefix=;
shift=$(( 32 - prefix ));
bitmask=""
for (( i=0; i < 32; i++ )); do
num=0
if [ $i -lt $prefix ]; then
num=1
fi
space=
if [ $(( i % 8 )) -eq 0 ]; then
space=" ";
fi
bitmask="${bitmask}${space}${num}"
done
echo $bitmask
}
bit_netmask_to_wildcard_netmask() {
bitmask=;
wildcard_mask=
for octet in $bitmask; do
wildcard_mask="${wildcard_mask} $(( 255 - 2#$octet ))"
done
echo $wildcard_mask;
}
#######################
## MAIN
#######################
for ip in $@; do
net=$(echo $ip | cut -d '/' -f 1);
prefix=$(echo $ip | cut -d '/' -f 2);
bit_netmask=$(prefix_to_bit_netmask $prefix);
wildcard_mask=$(bit_netmask_to_wildcard_netmask "$bit_netmask");
str=
for (( i = 1; i <= 4; i++ )); do
range=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
range="{0..$mask_octet}";
fi
str="${str} $range"
done
ips=$(echo $str | sed "s, ,\.,g"); ## replace spaces with periods, a join...
eval echo $ips | tr ' ' '2'
done
回答by scherand
I have extended @rberg script a little.
我稍微扩展了@rberg 脚本。
- check if the "network" you provide really is a network (use
-f
to skip the check) - handle netmasks greater than
/24
- 检查您提供的“网络”是否真的是网络(用于
-f
跳过检查) - 处理大于
/24
Maybe this is of use for someone.
也许这对某人有用。
#!/bin/bash
############################
## Methods
############################
prefix_to_bit_netmask() {
prefix=;
shift=$(( 32 - prefix ));
bitmask=""
for (( i=0; i < 32; i++ )); do
num=0
if [ $i -lt $prefix ]; then
num=1
fi
space=
if [ $(( i % 8 )) -eq 0 ]; then
space=" ";
fi
bitmask="${bitmask}${space}${num}"
done
echo $bitmask
}
bit_netmask_to_wildcard_netmask() {
bitmask=;
wildcard_mask=
for octet in $bitmask; do
wildcard_mask="${wildcard_mask} $(( 255 - 2#$octet ))"
done
echo $wildcard_mask;
}
check_net_boundary() {
net=;
wildcard_mask=;
is_correct=1;
for (( i = 1; i <= 4; i++ )); do
net_octet=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
if [ $(( $net_octet&$mask_octet )) -ne 0 ]; then
is_correct=0;
fi
fi
done
echo $is_correct;
}
#######################
## MAIN
#######################
OPTIND=1;
getopts "f" force;
shift $(( OPTIND-1 ));
for ip in $@; do
net=$(echo $ip | cut -d '/' -f 1);
prefix=$(echo $ip | cut -d '/' -f 2);
do_processing=1;
bit_netmask=$(prefix_to_bit_netmask $prefix);
wildcard_mask=$(bit_netmask_to_wildcard_netmask "$bit_netmask");
is_net_boundary=$(check_net_boundary $net "$wildcard_mask");
if [ $force != 'f' ] && [ $is_net_boundary -ne 1 ]; then
read -p "Not a network boundary! Continue anyway (y/N)? " -n 1 -r
echo ## move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_processing=1;
else
do_processing=0;
fi
fi
if [ $do_processing -eq 1 ]; then
str=
for (( i = 1; i <= 4; i++ )); do
range=$(echo $net | cut -d '.' -f $i)
mask_octet=$(echo $wildcard_mask | cut -d ' ' -f $i)
if [ $mask_octet -gt 0 ]; then
range="{$range..$(( $range | $mask_octet ))}";
fi
str="${str} $range"
done
ips=$(echo $str | sed "s, ,\.,g"); ## replace spaces with periods, a join...
eval echo $ips | tr ' ' '2'
fi
done
回答by Trevor Steen
Wanted to comment on an answer above but don't have the rep yet.
想对上面的答案发表评论,但还没有代表。
Using the top solution with NMAP I added this to my .bashrc
使用带有 NMAP 的顶级解决方案,我将其添加到我的 .bashrc
expand-ip() {
nmap -sL -n -iL "" | awk '/Nmap scan report/{print $NF}'
}
Now I can use this with just expand-ip targs
.
现在我可以将它与expand-ip targs
.
回答by George
fping -Aaqgr 1 10.1.1.0/24
Simplicity works best
简单效果最好
回答by mikky
This script should do. It's (almost) pure Bash. The seq
part can be replaced if a completely pure bash is required.
这个脚本应该可以。它(几乎)是纯 Bash。seq
如果需要完全纯的 bash,则可以更换该部件。
Since Bash apparently uses signed two-complement 4-byte integers, the script is limited to /8 mask maximum. I found ranges larger than /16 impractical anyway so this doesn't bother me at all. If someone knows a simple way to overcome this, please share :)
由于 Bash 显然使用带符号的两个补码 4 字节整数,因此该脚本仅限于 /8 掩码最大值。我发现范围大于 /16 无论如何都不切实际,所以这根本不打扰我。如果有人知道克服这个问题的简单方法,请分享:)
#!/usr/bin/env bash
base=${1%/*}
masksize=${1#*/}
[ $masksize -lt 8 ] && { echo "Max range is /8."; exit 1;}
mask=$(( 0xFFFFFFFF << (32 - $masksize) ))
IFS=. read a b c d <<< $base
ip=$(( ($b << 16) + ($c << 8) + $d ))
ipstart=$(( $ip & $mask ))
ipend=$(( ($ipstart | ~$mask ) & 0x7FFFFFFF ))
seq $ipstart $ipend | while read i; do
echo $a.$(( ($i & 0xFF0000) >> 16 )).$(( ($i & 0xFF00) >> 8 )).$(( $i & 0x00FF ))
done
Usage:
用法:
./script.sh 192.168.13.55/22
Tested with Bash version 4.4.23. YMMV.
使用 Bash 版本 4.4.23 进行测试。天啊。