Makefile中如何将命令输出赋值给变量并遍历对象数组
解决Makefile中遍历JSON数组访问字段的错误问题
问题场景
在Makefile中执行az graph query命令获取JSON格式结果,尝试将结果赋值给变量后遍历数组对象访问status字段时,出现错误:
/bin/bash: line 4: ${result.status}: bad substitution
make: *** [Makefile:23: check] Error 1
原Makefile代码:
QUERY := "securityresources | where type == 'microsoft.security/assessments' | summarize by assessmentKey=name | join kind=inner ( securityresources | where type == 'microsoft.security/assessments/subassessments' | extend assessmentKey = extract('.*assessments/(.+?)/.*',1, id) ) on assessmentKey | where properties.additionalData.assessedResourceType == 'ContainerRegistryVulnerability' | extend status = properties.status.code | extend severity = properties.status.severity" .ONESHELL: check: # az graph query -q ${QUERY} results="`az graph query -q ${QUERY}`" @for result in $$results.data; do echo "$${result.status}" done
az graph query返回的JSON示例:
{ "count": 10, "data" : [{"status":"healthy", "abc":"123"}, {"status":"unhealthy", "abc":"322"}, {"status":"healthy", "abc":"432"} ] }
错误原因
- Bash本身不支持直接解析JSON结构,
results变量存储的是整个JSON字符串,$$results.data无法提取数组内容,遍历的是字符串的字符而非JSON对象。 ${result.status}是JSON对象的属性访问语法,Bash不识别这种变量替换格式,因此报"bad substitution"错误。
解决方案
使用jq工具(专门的JSON处理工具)来解析和提取JSON数据,避免在Bash中直接处理JSON结构。以下是两种实现方式:
方式1:直接提取并输出指定字段
如果只需要输出status字段,可直接用jq一步完成:
QUERY := "securityresources | where type == 'microsoft.security/assessments' | summarize by assessmentKey=name | join kind=inner ( securityresources | where type == 'microsoft.security/assessments/subassessments' | extend assessmentKey = extract('.*assessments/(.+?)/.*',1, id) ) on assessmentKey | where properties.additionalData.assessedResourceType == 'ContainerRegistryVulnerability' | extend status = properties.status.code | extend severity = properties.status.severity" .ONESHELL: check: # 直接用jq提取data数组中每个对象的status字段并输出 @az graph query -q ${QUERY} | jq -r '.data[] | .status'
方式2:遍历JSON对象做复杂处理
如果需要对每个JSON对象执行更多操作,可先用jq将数组元素转为单行字符串,再在Bash中遍历处理:
QUERY := "securityresources | where type == 'microsoft.security/assessments' | summarize by assessmentKey=name | join kind=inner ( securityresources | where type == 'microsoft.security/assessments/subassessments' | extend assessmentKey = extract('.*assessments/(.+?)/.*',1, id) ) on assessmentKey | where properties.additionalData.assessedResourceType == 'ContainerRegistryVulnerability' | extend status = properties.status.code | extend severity = properties.status.severity" .ONESHELL: check: @az graph query -q ${QUERY} | jq -c '.data[]' | while read -r result; do # 用jq从单个JSON对象中提取字段 status=$(echo "$$result" | jq -r '.status') abc=$(echo "$$result" | jq -r '.abc') echo "状态: $$status, ABC值: $$abc" done
关键说明
- jq工具:需提前安装(可通过
apt install jq或brew install jq完成),它能高效处理JSON的解析、过滤和转换。 - Makefile变量转义:在Makefile的shell命令中,所有
$需要写成$$,避免被Make解析为Make变量。 - .ONESHELL:确保整个check目标的命令在同一个shell进程中执行,避免变量跨shell失效(多步shell操作时必备)。
内容的提问来源于stack exchange,提问作者Python coder
相关产品推荐
相关产品推荐

