我想我最好为此开始一个新的查询,因为我原来的查询已得到完全解答(谢谢!)。
我有两个文件,它们都是 postgresql 命令的输出。第一个(/tmp/inventory.list)是我原始查询的主题使用 bash 数组将表转换为 ini 文件,为此我使用 @choroba 善意建议的数组命令。鉴于我的第二个文件(/tmp/inventory2.list)的格式与第一个文件非常相似,我认为我可以调整数组脚本来类似地处理这个文件,但我显然把一些事情搞砸了。
我的输入文件 /tmp/inventory2.list 的格式为:
environment1 | hostname1.environment1.domain
environment1 | hostname2.environment1.domain
environment1 | hostname3.environment1.domain
environment2 | hostname4.environment2.domain
environment2 | hostname5.environment2.domain
environment3 | hostname6.environment3.domain
必须以分组格式读入并写入另一个文件:
[environment1]
hostname1.environment1.domain
hostname2.environment1.domain
hostname3.environment1.domain
[environment2]
hostname4.environment2.domain
hostname5.environment2.domain
[environment3]
hostname6.environment3.domain
环境分组之间必须有行空间,组名称必须按字母顺序显示,主机名必须在组内按字母顺序排序。每个环境组可能有多个主机名,但每个组只能显示一次。
让事情变得复杂的是,输入文件末尾有一个空行,我无法让我的 postgresql 查询省略它(-t 或 --tuples-only 删除通常写在末尾的行计数行,但不会' t 删除最后一个空行),因此需要将其删除并且不写入新的输出文件。
我尝试调整 @choroba 的数组命令来读取此文件并正确输出它,但是尽管它对于我的第一个文件完美地工作,但我的调整不起作用。我有:
1 #! /bin/bash
2
3 unset -v envs
4 unset -v hosts
5 declare -A envs
6 declare -A hosts
7 rm -f /tmp/hosts.txt
8
9 while IFS='| ' read -r certname role env; do
10 envs["$role.$env"]+="$certname"$'\n'
11 done < /tmp/inventory.list
12
13 for e in "${!envs[@]}" ; do
14 #
15 printf '%s\n' "$e"
16 done | sort | while read -r e ; do
17 printf '%s\n' "[$e]" "${envs[$e]}" >> /tmp/hosts.txt
18 done
19
20 while IFS='| ' read -r env certname; do
21 hosts["$env"]+="$certname"$'\n'
22 done < /tmp/inventory2.list
23
24 for f in "${!hosts[@]}" ; do
25 printf '%s\n' "$f"
26 done | sort | while read -r f ; do
27 printf '%s\n' "[$f]" "${hosts[$f]}" >> /tmp/hosts1.txt
28 done
第 9 行到第 18 行(以及相关的第 3 行和第 5 行)是 @choroba 给我的代码,并且在读入的文件 /tmp/inventory.list 上完美运行。
第 20 至 28 行(以及相关的第 4 行和第 6 行)是我为处理第二个文件 /tmp/inventory2.list 而进行的修改。运行时,我收到错误:
line 21: hosts["$env"]: bad array subscript
我已经对此进行了几个小时的修改,但看不出我的改编片段中有什么问题。请问有人有什么想法吗?
答案1
您在输入文件中提到了一个空行;如果它在 /tmp/inventory2.list 中,那就是问题所在。
通过多种方式解决;一种方法是在尝试使用 $env 变量之前测试它:
[ -n "$env" ] && hosts["$env"]+="$certname"$'\n'
另一种方法是在读取文件之前先 grep 查找文件中的任何字符:
grep . inventory2.list | while IFS='| ' read -r env certname; do
hosts["$env"]+="$certname"$'\n'
done
(如果你的“空白”行有空格,请调整 grep;类似grep [a-z]
)