
本文介绍如何在 Python 中替代 jq '.cis[].properties.cloud_vm_display_name' | grep -v null 命令,从多个结构相似但数组长度不一的 JSON 文件中稳健提取 cloud_vm_display_name 字段值,并规避空值与语法错误。
本文介绍如何在 Python 中替代 `jq '.cis[].properties.cloud_vm_display_name' | grep -v null` 命令,从多个结构相似但数组长度不一的 JSON 文件中稳健提取 `cloud_vm_display_name` 字段值,并规避空值与语法错误。
在 Shell 中用 jq 处理 JSON 数组非常简洁(如 .cis[].properties.cloud_vm_display_name),但迁移到 Python 时,不能像 data['cis'][] 这样使用空索引——这是语法错误(SyntaxError: invalid syntax)。正确做法是遍历 data['cis'] 列表,逐项访问嵌套字段,并加入空值/无效值过滤逻辑。
以下是一个完整、健壮的处理流程:
✅ 正确提取方式(推荐)
import json
# 示例:加载单个 JSON 文件(实际中可循环读取多个文件)
with open("server1.json", "r") as f:
data = json.load(f)
# 提取所有非 null 的 cloud_vm_display_name(严格匹配字符串 'null')
names = []
for cis_item in data.get("cis", []):
props = cis_item.get("properties", {})
name = props.get("cloud_vm_display_name")
# 注意:这里判断 name 是否为 None 或字符串 "null",而非模糊包含 'null'
if name is not None and name != "null":
names.append(name)
print(names) # 输出: ['azuXXXXX', 'azuXXXXX', 'azuXXXXXX', ...]✅ 更简洁:列表推导式(一行高效实现)
names = [
cis["properties"]["cloud_vm_display_name"]
for cis in data.get("cis", [])
if cis.get("properties", {}).get("cloud_vm_display_name") not in (None, "null")
]⚠️ 注意:原始 grep -v null 实际会误删含 "null" 子串的合法值(如 "anulled-vm")。应改用精确比对 != "null" 或检查是否为 None,这才是语义等价的 Python 写法。
✅ 批量处理多个 JSON 文件
import glob
import json
all_names = []
for filepath in glob.glob("*.json"): # 匹配所有 JSON 文件
try:
with open(filepath, "r") as f:
data = json.load(f)
for cis in data.get("cis", []):
name = cis.get("properties", {}).get("cloud_vm_display_name")
if name and name != "null": # 安全判空:非 None、非空字符串、非 "null"
all_names.append(name)
except (json.JSONDecodeError, OSError) as e:
print(f"警告:跳过无效文件 {filepath} — {e}")
print(all_names)? 补充说明:为什么不用 'null' in name?
原始答案中提到 if not 'null' in name 有歧义——它会错误过滤 "cloud_null_server" 等合法名称。真实场景中,JSON 字段若为空,通常为 null(Python 中为 None)或显式字符串 "null"。因此,推荐统一用 name not in (None, "null", "") 做防御性判断。
✅ 总结
- ❌ 错误:data['cis'][] —— Python 不支持空索引语法;
- ✅ 正确:用 for 循环或列表推导式遍历 data['cis'];
- ✅ 安全:始终使用 .get() 避免 KeyError,并显式校验 None 和 "null";
- ✅ 扩展:结合 glob、异常处理,即可无缝替代 cat * | jq ... | grep 流水线。
通过以上方法,你不仅能精准复现 jq 的功能,还能获得更强的错误控制、类型安全与可维护性。