从字符串数组中选择有效的 IP
Picking valid IPs from an array of strings
在我的用例中,我从列表中过滤某些 IPv4 并将它们放入数组中以用于进一步的任务:
readarray -t firstarray < <(grep -ni '^ser*' IPbook.file | cut -f 2 -d "-")
结果输出为:
10.8.61.10
10.0.10.15
172.0.20.30
678.0.0.10
如您所见,最后一行不是 IP,因此我迫切希望在 FIRSTARRAY 上添加一些正则表达式检查。
我不想保存附属文件来使用它们,所以我正在寻找一些 "on-the-fly" 选项来正则表达式 firstarray。我尝试了以下方法:
for X in "${FIRSTARRAY[@]}"; do
readarray -t SECONDARRAY < <(grep -E '\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}\b' "$X")
done
但在输出中我看到系统认为 $X 是一个 file/dir,并且没有处理该值,即使它清楚地看到它:
line ABC: 172.0.20.30: No such file or directory
line ABC: 678.0.0.10: No such file or directory
我做错了什么,最好的方法是什么?
您正在将 "$X"
作为参数传递给 grep
,因此它被视为一个文件。使用此处字符串 <<<
代替:
for X in "${firstarray[@]}"; do
readarray -t secondarray < <(grep -E '\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}\b' <<< "$X")
done
你最好编写一个函数来验证 IP,而不是仅仅依赖 :
#!/bin/bash
validate_ip() {
local arr element
IFS=. read -r -a arr <<< "" # convert ip string to array
[[ ${#arr[@]} != 4 ]] && return 1 # doesn't have four parts
for element in "${arr[@]}"; do
[[ $element =~ ^[0-9]+$ ]] || return 1 # non numeric characters found
[[ $element =~ ^0[1-9]+$ ]] || return 1 # 0 not allowed in leading position if followed by other digits, to prevent it from being interpreted as on octal number
((element < 0 || element > 255)) && return 1 # number out of range
done
return 0
}
然后遍历你的数组:
for x in "${firstarray[@]}"; do
validate_ip "$x" && secondarray+=("$x") # add to second array if element is a valid IP
done
问题是,您将一个参数传递给 grep
命令,它期望读取标准输入。
您可以在第一个命令中使用正则表达式来过滤 IP 地址:
readarray -t firstarray < <(grep -ni '^ser*' IPbook.file | cut -f 2 -d "-" | grep -E '\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}\b' )
那么你只有 firstarray
中的 IP 地址。
在我的用例中,我从列表中过滤某些 IPv4 并将它们放入数组中以用于进一步的任务:
readarray -t firstarray < <(grep -ni '^ser*' IPbook.file | cut -f 2 -d "-")
结果输出为:
10.8.61.10
10.0.10.15
172.0.20.30
678.0.0.10
如您所见,最后一行不是 IP,因此我迫切希望在 FIRSTARRAY 上添加一些正则表达式检查。 我不想保存附属文件来使用它们,所以我正在寻找一些 "on-the-fly" 选项来正则表达式 firstarray。我尝试了以下方法:
for X in "${FIRSTARRAY[@]}"; do
readarray -t SECONDARRAY < <(grep -E '\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}\b' "$X")
done
但在输出中我看到系统认为 $X 是一个 file/dir,并且没有处理该值,即使它清楚地看到它:
line ABC: 172.0.20.30: No such file or directory
line ABC: 678.0.0.10: No such file or directory
我做错了什么,最好的方法是什么?
您正在将 "$X"
作为参数传递给 grep
,因此它被视为一个文件。使用此处字符串 <<<
代替:
for X in "${firstarray[@]}"; do
readarray -t secondarray < <(grep -E '\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}\b' <<< "$X")
done
你最好编写一个函数来验证 IP,而不是仅仅依赖
#!/bin/bash
validate_ip() {
local arr element
IFS=. read -r -a arr <<< "" # convert ip string to array
[[ ${#arr[@]} != 4 ]] && return 1 # doesn't have four parts
for element in "${arr[@]}"; do
[[ $element =~ ^[0-9]+$ ]] || return 1 # non numeric characters found
[[ $element =~ ^0[1-9]+$ ]] || return 1 # 0 not allowed in leading position if followed by other digits, to prevent it from being interpreted as on octal number
((element < 0 || element > 255)) && return 1 # number out of range
done
return 0
}
然后遍历你的数组:
for x in "${firstarray[@]}"; do
validate_ip "$x" && secondarray+=("$x") # add to second array if element is a valid IP
done
问题是,您将一个参数传递给 grep
命令,它期望读取标准输入。
您可以在第一个命令中使用正则表达式来过滤 IP 地址:
readarray -t firstarray < <(grep -ni '^ser*' IPbook.file | cut -f 2 -d "-" | grep -E '\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}\b' )
那么你只有 firstarray
中的 IP 地址。