从bash中的数组中获取唯一的值
1. 概述
Bash 是安装在几乎所有 Linux 系统上的多功能 shell。
除了作为交互式 shell 的价值之外,bash 还可以用于自动执行各种任务。这些任务通常会处理我们的数据列表:例如,文件列表或 IP 地址列表。
我们可以将这些列表组织成数组 。Bash 使用索引数组(我们通过编号引用项目)和关联数组(我们通过名称引用项目)。关联数组在其他编程语言中通常称为映射或字典。
在本教程中,我们将一些列表分配给数组。然后,我们将研究从数组中筛选出重复项的方法,因此它们只包含唯一条目而没有重复项。
2. 声明和使用数组
Bash Arrays 在本网站的其他地方进行了深入介绍。
简而言之,我们需要知道如何声明这两种数组(索引数组和关联数组)。我们还需要知道如何引用整个数组。
我们可以使用括号定义索引数组:
ip_addrs=(192.168.2.101 192.168.2.105 192.168.2.201 192.168.2.110)
要使用整个数组而不是单个索引,我们使用 @ 符号而不是数字。
这让我们可以循环遍历数组中的所有元素,而无需跟踪索引。例如,假设我们想对每个地址执行一次 ping 操作:
for ip in ${ip_addrs[@]}; do
ping -D -c1 $ip
done
2.1.关联数组
对于某些数据,我们想要的不仅仅是一个编号列表。关联数组让我们为数据(“值”)命名(“键”)。NoSQL 数据库也经常以这种方式组织数据。
我们可以像这样一次分配几个键/值对:
declare -A ips_by_hostname=([mysql]=192.168.2.101 [nginx]=192.168.2.99 [smtp]=192.168.2.105)
让我们记住首先使用declare -A将变量“声明”为关联数组。
我们还可以生成一个包含所有值或所有键的数组。
要列出所有关联数组的值,我们使用与索引数组类似的语法:
$ echo "${ips_by_hostname[@]}"
192.168.2.101 192.168.2.105 192.168.2.99
要查看键,请在数组变量名称前添加一个感叹号:
for host in "${!ips_by_hostname[@]}"; do
echo "key: $host value: ${ips_by_hostname[$host]}"
done
key: mysql value: 192.168.2.101
key: smtp value: 192.168.2.99
key: nginx value: 192.168.2.105
3. 只有独特的价值
那么让我们回到我们最初的问题:当我们的数组包含重复项时,有什么简单的方法可以删除它们?
3.1. 分配给关联数组键
关联数组的键对于该数组必须始终是唯一的。一键,一值。
我们可以利用它来发挥我们的优势。如果我们遍历一个数组并将每个项目分配给关联数组的键,则该数组的键将是原始数组的一组唯一值:
declare -a ip_addrs=(192.168.1.101 192.168.1.105 192.168.1.105 192.168.1.106)
declare -A uniq_tmp
for ip in "${ip_addrs[@]}"; do
uniq_tmp[$ip]=0 # assigning a placeholder
done
echo "unique: ${!uniq_tmp[@]}" # only the keys
这将输出三个 IP 地址,省略重复的 192.168.1.105。该解决方案的优点是全部在 bash 中工作,而不是运行任何其他程序。
3.2. 使用sort -u
在编写 shell 脚本时,我们还有其他选择。我们可以通过GNUsort实用程序 传递我们的数组。
这将改变项目的顺序,所以如果它在我们的特定脚本中很重要,请记住这一点。
sort命令逐行对输入进行排序,因此我们需要将数组拆分为多行。
sort命令的*-u*选项会丢弃任何重复的行。
所以我们可以像这样使用我们的 IP 地址数组:
uniqs_arr=($(for ip in "${ip_addrs[@]}"; do echo "${ip}"; done | sort -u))
现在我们有一个唯一的排序值数组。
3.3. 使用tr和awk
一旦我们开始使用其余的 Unix 工具集合,我们就会开始到处寻找解决方案。除了 bash 之外,一个强大的工具是awk :
uniqs_arr=($(tr ' ' '\n' <<<"${ip_addrs[@]}" | awk '!u[$0]++' | tr '\n' ' '))
这进入了更复杂的领域。但要分解它:
- 我们需要再次将数组分成单独的行。这一次,我们使用tr 将项目之间的空格转换为换行符 (\n)。
- 我们通过管道将其传递给awk,并让它只引用唯一的行。
- 然后我们再次将输出转换回数组,再次使用tr。
这种方法的优点是我们保留了数组元素的顺序。