假设我有以下JSON文档(受this post启发)
初始文件
{
"key": "value",
"ips": [
{
"ip": "1.2.3.4",
"macAddress": "ac:5f:3e:87:d7:1a"
},
{
"ip": "5.6.7.8",
"macAddress": "ac:5f:3e:87:d7:2a"
},
{
"ip": "9.10.11.12",
"macAddress": "ac:5f:3e:87:d7:3a"
},
{
"ip": "13.14.15.16",
"macAddress": "42:12:20:2e:2b:ca"
}
]
}
字符串
现在我想读取每个macAddress
,将其传递给哈希函数(例如md5sum
),并将结果写回JSON文档。
期望输出
{
"key": "value",
"ips": [
{
"ip": "1.2.3.4",
"macAddress": "45ee585278a0717c642ff2cb25a8e441"
},
{
"ip": "5.6.7.8",
"macAddress": "ab47bf90cb9f385127977569e676ce70"
},
{
"ip": "9.10.11.12",
"macAddress": "a5e9785db428e3956a47776dbd00fc91"
},
{
"ip": "13.14.15.16",
"macAddress": "f75d61937f70252ff139adee241daab4"
}
]
}
型
目前我有下面的shell脚本,但我认为它可以做得更优雅......最好在一行程序。
json_doc="{\"key\": \"value\", \"ips\": [{\"ip\":\"1.2.3.4\",\"macAddress\":\"ac:5f:3e:87:d7:1a\"},{\"ip\":\"5.6.7.8\",\"macAddress\":\"ac:5f:3e:87:d7:2a\"},{\"ip\":\"9.10.11.12\",\"macAddress\":\"ac:5f:3e:87:d7:3a\"},{\"ip\":\"13.14.15.16\",\"macAddress\":\"42:12:20:2e:2b:ca\"}]}"
ip_list=$(jq -c '.ips[]' <<< "$json_doc" |
while read -r jsonline ; do
hashmac="$(jq -s -j '.[] | .macAddress' <<<"$jsonline" | md5sum | cut -d ' ' -f1)"
jq --arg hashmac "$hashmac" -s -r '.[] | .macAddress |= "\($hashmac)"' <<<"$jsonline"
done | jq -s)
# Update json document with ip list containing hashed mac addresses
jq --argjson ips "$ip_list" '.ips = $ips' <<<"$json_doc"
型
2条答案
按热度按时间irtuqstp1#
peak的answer是链接问题的变体。
jq
的两次调用,首先用于计算md5哈希值,然后使用reduce
将计算结果重新构造回原始JSON字符串
第二个
jq
调用应该仔细阅读。初始参数-s -R
用于将for循环创建的多行非JSON输出阅读到jq的上下文中。而--slurpfile
参数用于将计算的哈希更新回原始JSON。slurp操作将整个文件带入内存。因此,这个命令对于非常大的JSON文件可能无效。
46qrfjad2#
另一种方法是使用
jq
将JSON分解为标量行,然后过滤并处理jq
之外的相关行,并最终通过第二次调用jq
重新组装该流。这里有一个使用
jq
的流表示的例子,即jq -c . --stream
用于分解,jq -n 'fromstream(inputs)'
用于重组,awk
用于实际处理,因为它可以很容易地按行读取和过滤,改变它的一部分,和shell来执行外部任务。要过滤像[["ips",0,"macAddress"],"ac:5f:3e:87:d7:1a"]
这样的行,同时通过像[["ips",0,"ip"],"1.2.3.4"]
或[["ips",0,"macAddress"]]
这样的行,一种简单的方法是将每行解释为用双引号"
分隔的列,然后过滤匹配给定内容的第2和第4列,第6列不为空。(鲁棒性可明显提高;这只是一个例子),然后替换第6列(使用getline
),printf %s
的输出是第6列的值,然后是您的md5sum
和cut
处理。(使用onetrueawk/awk版本20231124和GNU Awk 5.3.0进行了测试。)字符串
下面是另一个更健壮的示例,它“手动”将输入分解为值和路径,同时还附加了一个标志来标记需要进一步处理的标量(通过
.ips[].macAddress
路径表达式jq
查询),转换成像"1.2.3.4" ["ips",0,"ip"] false
或"ac:5f:3e:87:d7:1a" ["ips",0,"macAddress"] true
这样的行。这个例子的处理部分只使用POSIX-兼容的shell特性,如read
,通过行来进行重定向,一个case
语句,基于该标志进行偏转,和tr
以及参数扩展来提取IP最后的jq
composer然后使用reduce
收集行,并使用setpath
连续构建输出。型
对于给定的输入,两个示例都输出
型