Hel*_*enH 5 bash text-processing
我在采用这种格式的输出文件(“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)
Run Code Online (Sandbox Code Playgroud)
并以不同的格式将其写到另一个文件中:
[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
Run Code Online (Sandbox Code Playgroud)
abc
和def
是分配给服务器的角色,每个角色可以有多个服务器,以及同名但在不同环境中的角色。我必须将每个主机名分成唯一的 [role.environment] 组,另外,完全删除文件的最后一行,即行计数(该文件是 sql 查询的输出)。
我可以读取文件,去除管道和空格并分配/输出角色/环境分组,没问题:
#! /bin/bash
while IFS='| ' read -r certname role env; do
printf '%s\n' "[""$role"".""$env""]"
done < "/tmp/inventory.list"
Run Code Online (Sandbox Code Playgroud)
...它巧妙地为我提供了角色/环境组名称:
[abc.environment1]
[abc.environment2]
[def.environment1]
[def.environment2]
Run Code Online (Sandbox Code Playgroud)
但我无法弄清楚如何打印出链接到每个组名下的每个角色/环境组的主机名,我也无法弄清楚如何让我的脚本忽略最后一行计数行。我猜我必须进一步将我的角色和环境字段(第二个和第三个字段)分配给它自己的数组,然后引用它来获取链接到每个唯一分组的主机名,但我不知道如何实现这一点。请问有人可以建议吗?
我会使用文本实用程序来处理文本,而不是使用 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
Run Code Online (Sandbox Code Playgroud)
请注意,不能保证条目的顺序。使用 GNU awk
,添加 aBEGIN{PROCINFO["sorted_in"] = "@ind_str_asc"}
以根据键进行排序。
根据您使用的 RDBMS,您还可以让它以正确的格式显示(例如使用GROUP_CONCAT
inmysql
或string_agg
in postgre)。
首先,您也可以要求您的 RDBMS 查询实用程序将输出格式化为更适合后处理的格式(例如,去除页眉、页脚和使用制表符分隔值)。
使用关联数组来存储每个角色和环境的证书名称。
#! /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
Run Code Online (Sandbox Code Playgroud)
要对部分进行排序,您可以打印键,对它们进行排序,然后读回它们并输出关联的值:
for e in "${!envs[@]}" ; do
printf '%s\n' "$e"
done | sort | while read -r e ; do
printf '%s\n' "[$e]" "${envs[$e]}"
done
Run Code Online (Sandbox Code Playgroud)