我想检查用户输入是否是 bash 中的有效 IP 地址/CIDR,并且我正在使用正则表达式来执行此操作。所以有效的 CIDR 应该是 0-32,对于 IP,(1-254).(1-255).(1-255).(1-255)/(1-32)
所以我当前的代码是:
read -p "Input: " ip_address
if [[ $ip_address =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]];
then
echo "VALID"
else
echo "NOT VALID"
fi
但它过于慷慨并且接受一些无效的组合。因此,有效的 IP 地址/CIDR 组合应该是:10.11.11.11/24
或254.255.255.255/23
,无效是256.19.11.11/24
因为第一个八位字节高于 255 或者222.222.222.222/33
这里的 CIDR 高于 32。除了正则表达式之外,还有其他方法来检查有效的 IP 地址/CIDR 吗?
答案1
要正确处理 IP 地址或 CIDR 的验证,请使用专门为此设计的库函数,例如模块cidrvalidate()
中的 Perl 函数Net::CIDR
:
$ perl -MNet::CIDR=cidrvalidate -e 'printf("%s\n", cidrvalidate($ARGV[0]) ? "valid" : "invalid")' -- 1.2.3.0/24
valid
$ perl -MNet::CIDR=cidrvalidate -e 'printf("%s\n", cidrvalidate($ARGV[0]) ? "valid" : "invalid")' -- 1.2.3.0/2
invalid
$ perl -MNet::CIDR=cidrvalidate -e 'printf("%s\n", cidrvalidate($ARGV[0]) ? "valid" : "invalid")' -- 1.2.3.0
valid
看看perldoc Net::CIDR
这个库还能做什么。
在上面的示例中不是--
必需的,但可以用于用户的任意输入,否则,perl
如果该输入以 开头,则该输入将被视为选项-
。
下面的方法是您尝试的变体,它不关心无效的网络掩码。
0 到 255 之间的正十进制整数可以通过以下方式匹配
[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]
0 到 32 之间的正十进制整数可以通过以下方式匹配
[0-9]|[12][0-9]|3[012]
使用这个:
#!/bin/bash
n='([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
m='([0-9]|[12][0-9]|3[012])'
IFS= read -rp 'Input: ' ipaddr
if [[ $ipaddr =~ ^$n(\.$n){3}/$m$ ]]; then
printf '"%s" is a valid CIDR\n' "$ipaddr"
else
printf '"%s" is not valid\n' "$ipaddr"
fi
表达方式
^$n(\.$n){3}/$m$
将扩展为跨越给定字符串完整长度的有效 CIDR 的完整正则表达式。
另一种明显的方法是阅读数字在给定的字符串中,测试前四个是否在 0-255 范围内,第五个是否在 0-32 范围内:
#!/bin/bash
IFS='./' read -rp 'Input: ' a b c d e
for var in "$a" "$b" "$c" "$d" "$e"; do
case $var in
""|*[!0123456789]*)
printf 'not a valid number: %s\n' "$var"
exit 1
esac
done
ipaddr="$a.$b.$c.$d/$e"
if [ "$a" -ge 0 ] && [ "$a" -le 255 ] &&
[ "$b" -ge 0 ] && [ "$b" -le 255 ] &&
[ "$c" -ge 0 ] && [ "$c" -le 255 ] &&
[ "$d" -ge 0 ] && [ "$d" -le 255 ] &&
[ "$e" -ge 0 ] && [ "$e" -le 32 ]
then
printf '"%s" is a valid CIDR\n' "$ipaddr"
else
printf '"%s" is not valid\n' "$ipaddr"
fi
这里我们将五个单词读入五个变量。输入的字符串在读取.
时被分割成单词/
(这意味着3/3/3/3.2
将被解析为有效,但请参见$ipaddr
代码)。任何非整数数据读取都会触发脚本退出。然后我们开始根据有效范围测试它们的值。如果任何测试失败,则输入的地址无效。
答案2
这就是我用的:
#!/bin/bash
function checkCidrFormat {
local ipCidr="${1}"
local validIpCidr
validIpCidr='(^([1-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\.([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\.([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\.([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\/([1-9]|[1-2][0-9]|[3][0-2]))$'
if [[ $ipCidr =~ ^$validIpCidr ]]; then
echo "valid format"
return 0
else
echo "not valid format"
return 1
fi
}
while true;
do
read -rp "ip cidr (eg. 172.16.16.32/27): " cidr
if checkCidrFormat "${cidr}"; then
echo "do something"
fi
done