使用 bash 数组将表转换为 ini 文件

使用 bash 数组将表转换为 ini 文件

我面临以下格式的输出文件(“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

abcdef是分配给服务器的角色,每个角色可以有多个服务器,以及同名但在不同环境中的角色。我必须将每个主机名分解为唯一的 [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_CONCATmysql或者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}'

相关内容