![Bash:提取 IPv4 地址的四个部分之一](https://linux22.com/image/126576/Bash%EF%BC%9A%E6%8F%90%E5%8F%96%20IPv4%20%E5%9C%B0%E5%9D%80%E7%9A%84%E5%9B%9B%E4%B8%AA%E9%83%A8%E5%88%86%E4%B9%8B%E4%B8%80.png)
我们可以使用语法${var##pattern}
并${var%%pattern}
提取 IPv4 地址的最后一部分和第一部分:
IP=109.96.77.15
echo IP: $IP
echo 'Extract the first section using ${var%%pattern}: ' ${IP%%.*}
echo 'Extract the last section using ${var##pattern}: ' ${IP##*.}
我们如何使用参数扩展提取 IPv4 地址的第二或第三部分?
这是我的解决方案:我使用数组并更改 IFS 变量。
:~/bin$ IP=109.96.77.15
:~/bin$ IFS=. read -a ArrIP<<<"$IP"
:~/bin$ echo ${ArrIP[1]}
96
:~/bin$ printf "%s\n" "${ArrIP[@]}"
109
96
77
15
我还使用 、 和 命令编写了一些awk
解决sed
方案cut
。
现在,我的问题是:是否有一个更简单的解决方案参数扩展哪个不使用数组和IFS改变?
答案1
假设 IFS 的默认值,您可以使用以下命令将每个八位字节提取到它自己的变量中:
read A B C D <<<"${IP//./ }"
或者放入数组中:
A=(${IP//./ })
答案2
我确实意识到您特别要求一个 DID NOT 暂时重新定义的解决方案IFS
,但我有一个您没有涵盖的甜蜜而简单的解决方案,所以这里是:
IFS=. ; set -- $IP
这个简短的命令会将您的 IP 地址元素放入 shell 的位置参数 $1
, $2
, $3
, $4
.但是,您可能需要先保存原始文件IFS
,然后再恢复它。
谁知道?也许您会重新考虑并接受这个答案,因为它简洁有效。
(这之前被错误地给出为IFS=. set -- $IP
)
答案3
您的问题陈述可能比您预期的更自由一些。冒着利用漏洞的风险,这是解决方案穆鲁提到:
first=${IP%%.*}
last3=${IP#*.}
second=${last3%%.*}
last2=${last3#*.}
third=${last2%.*}
fourth=${last2#*.}
echo "$IP -> $first, $second, $third, $fourth"
这有点笨拙。它定义了两个一次性变量,并且不容易适应处理更多部分(例如,对于 MAC 或 IPv6 地址)。 谢尔盖·科洛迪亚兹内的回答启发我将上述概括为:
slice="$IP"
count=1
while [ "$count" -le 4 ]
do
declare sec"$count"="${slice%%.*}"
slice="${slice#*.}"
count=$((count+1))
done
这集合sec1
、sec2
和,可以通过以下方式sec3
验证sec4
printf 'Section 1: %s\n' "$sec1"
printf 'Section 2: %s\n' "$sec2"
printf 'Section 3: %s\n' "$sec3"
printf 'Section 4: %s\n' "$sec4"
- 该
while
循环应该很容易理解——它迭代四次。 - Sergiy 选择了
slice
一个变量的名称来代替我的第一个解决方案(上面)中的last3
和。last2
declare sec"$count"="value"
是一种分配给sec1
,sec2
,的方法sec3
,当是, ,和sec4
时。有点像,但更安全。count
1
2
3
4
eval
- 这
value
,"${slice%%.*}"
, 类似于我原来的答案分配给first
,second
和 的值third
。
答案4
使用 zsh,您可以嵌套参数替换:
$ ip=12.34.56.78
$ echo ${${ip%.*}##*.}
56
$ echo ${${ip#*.}%%.*}
34
这在 bash 中是不可能的。