对于BASH,JSON和jq,我是全新的(实习生,实习经验不到两周)。但是我已经被赋予了一个迭代地从数组中替换JSON对象值的任务。我设法编写了以下代码。
我正在尝试将json文件中的键值" name",以递增方式替换为存储在另一个文本文件中的数组中的名称。基本上只是更新节点的名称。
以下是要替换的JSON文件的片段。整个文件太大了,不能在这里发布。 但是关键的路径" name"是" .lab.racks []。nodes [] .name"
"roles": [
"bla bla",
"bla bla"
],
"name": "Node1",
"power": {
"address": "10.182.149.145",
"type": "bla bla",
"user": "bla bla",
"pass": "bla bla "
},
" name":" Node1"必须更换为" name":" Tom-cat"。 Tom-cat的名称是动态生成的,每次运行Metal as a Service(MaaS)脚本时都会更改。这个名字" Tom-cat"并且MaaS生成的所有其他新名称都被删除(使用awk)并存储在文本文件newhostnames.txt中
文本文件看起来像这样
#newhostnames.txt
Tom-cat
Lucky-worm
Wom-bat
所以我们的目标是取代"名称"来自demolabconfig.json的密钥,其名称存储在文本文件中。
"name": "Node1" must be replaced as "name":"Tom-cat"
];
.....
.....
],
"name": "Node2" must be replaced as "name":"Lucky-worm"
];
.....
.....
],
"name": "Node3" must be replaced as "name":"Wom-bat"
为密钥"节点":.lab.racks []。节点[$ i] .name
完成索引。代码:
readarray -t array < newhostnames.txt
array=("${array[@]:1}")
array_length=${#array[@]}
for((i=0;i<${array_length};i++));
do
declare -x NEW_NODENAME
OLD_NODENAME=$(jq -r ".lab.racks[].nodes[$i].name" demolabconfig.json)
echo "$OLD_NODENAME"
NEW_NODENAME="${array[i]}"
echo "$NEW_NODENAME"
jq ".lab.racks[].nodes[$i].name=env.NEW_NODENAME" demolabconfig.json > newdemolabconfig.json
done
但是代码只替换最后一个$ i的最后一个值,即最后一个key_value对。所有其他前面的节点都保留与原始JSON文件中相同的名称。
如果值已经更新,我尝试使用if语句来中断循环,因此不会从旧的demolabconfig.json文件重新编写。但那也行不通!
if [[ "$OLD_NODENAME" -ne "$NEWNODENAME" ]]; then
jq ".lab.racks[].nodes[$i].name=env.NEW_NODENAME" demolabconfig.json > newdemolabconfig.json
else
break
fi
这个if循环是用while循环而不是for循环编写的。这将使用null替换姓氏。
请建议我如何修复此错误并改进我的代码。谢谢:))
答案 0 :(得分:1)
这里的目标应该是尽可能少地调用jq。因此,我们提出了一个只涉及两个电话的解决方案 到jq,不论&#34;名称的数量&#34;在newhostnames.txt。
首先让我们假设input.json包含以下内容:
{"nodes":[{"name":"old1"},{"name":"old2"},{"name":"old3"}]}
我们还假设以下jq程序在文件program.jq中:
reduce range(0; $newhostnames | length) as $i (.;
.nodes[$i].name = $newhostnames[$i])
然后调用:
jq -c --slurpfile newhostnames <(jq -nR inputs newhostnames.txt ) \
-f program.jq input.json
产生
{"nodes":[{"name":"Tom-cat"},{"name":"Lucky-worm"},{"name":"Wom-bat"}]}
( - c命令行选项产生压缩输出。)
如果你的shell不支持上面的调用,你可以(例如)将jq -nR inputs newhostnames.txt
的输出放在一个临时文件中。
当然,将.txt文件转换为JSON数组或JSON字符串流的附属任务可以通过其他方式完成。
如果newhostnames.txt有可能包含不需要的空白行,那么跳过它们的一种方法是在program.jq中添加一行,使它看起来像这样:
($newhostnames | map(select(length>0))) as $newhostnames
| reduce range(0; $newhostnames | length) as $i (.;
.nodes[$i].name = $newhostnames[$i])
请注意,$ -variable名称可以重复使用。