我面临以下格式的输出文件(“inventory.list”)的挑战:
hostname1.env1.domain | abc | environment1
hostname2.env1.domain | abc | environment1
hostname3.env2.domain | abc | environment2
hostname4.env2.domain | abc | environment2
hostname5.env1.domain | def | environment1
hostname6.env2.domain | def | environment2
(6 rows)
并将其以不同的格式写入另一个文件:
[abc.environment1]
hostname1.env1.domain
hostname2.env1.domain
[abc.environment2]
hostname3.env2.domain
hostname4.env2.domain
[def.environment1]
hostname5.env1.domain
[def.environment2]
hostname6.env2.domain
abc
和def
是分配给服务器的角色,每个角色可以有多个服务器,以及同名但在不同环境中的角色。我必须将每个主机名分解为唯一的 [role.environment] 组,此外,完全删除文件的最后一行,即行计数(该文件是 sql 查询的输出)。
我可以读取文件,去掉管道和空格并分配/输出角色/环境分组,没有问题:
#! /bin/bash
while IFS='| ' read -r certname role env; do
printf '%s\n' "[""$role"".""$env""]"
done < "/tmp/inventory.list"
...这整齐地给了我角色/环境组名称:
[abc.environment1]
[abc.environment2]
[def.environment1]
[def.environment2]
但我无法弄清楚如何打印出链接到每个组名称下的每个角色/环境组的主机名,我也无法弄清楚如何让我的脚本忽略最后一个行计数行。我猜我必须进一步将我的角色和环境字段(第二个和第三个字段)分配给它自己的数组,然后引用它来获取链接到每个唯一分组的主机名,但我不知道如何实现这一点。有人可以建议吗?
答案1
我会使用文本实用程序来处理文本而不是使用 shell 循环来处理文本(尽管在这里,IFS=' |'
很适合您的情况)。喜欢:
awk -F ' *[|] *' '
NF == 3 {host[$2"."$3] = host[$2"."$3] $1 "\n"}
END{for (i in host) print "[" i "]\n" host[i]}' < file
请注意,不保证条目的顺序。使用 GNU awk
,添加一个BEGIN{PROCINFO["sorted_in"] = "@ind_str_asc"}
基于键的排序。
根据您使用的 RDBMS,您还可以让它以正确的格式显示(例如使用GROUP_CONCAT
在mysql
或者string_agg
在postgre中)。
首先,您还可以要求 RDBMS 查询实用程序将输出格式化为更适合后处理的格式(例如,去掉页眉、页脚,并使用制表符分隔值)。
答案2
使用关联数组来存储每个角色和环境的证书名称。
#! /bin/bash
unset -v envs
declare -A envs
while IFS='| ' read -r certname role env; do
envs["$role.$env"]+="$certname"$'\n'
done < /tmp/inventory.list
for e in "${!envs[@]}" ; do
printf '%s\n' "[$e]" "${envs[$e]}"
done
要对这些部分进行排序,您可以打印键,对它们进行排序,然后读回它们并输出关联的值:
for e in "${!envs[@]}" ; do
printf '%s\n' "$e"
done | sort | while read -r e ; do
printf '%s\n' "[$e]" "${envs[$e]}"
done
答案3
Perl 魔法:
$ perl -lne '@F=split(/\s*\|\s*/); push @{$k{"$F[1].$F[2]"}},$F[0];
END{foreach (keys(%k)){print "[$_]"; print join "\n",@{$k{$_}}} }' file
[abc.environment1]
hostname1.env1.domain
hostname2.env1.domain
[def.environment1]
hostname5.env1.domain
[abc.environment2]
hostname3.env2.domain
hostname4.env2.domain
[def.environment2]
hostname6.env2.domain
答案4
使用 awk 的一种方法:
$ sed 's/ //g' file | awk -F"|" '{x="["$2"."$3"]";}!(x in a){print x;a[x];}{print $1}'