如何使用jq在bash脚本中删除JSON数组指定元素并原地更新文件
未生效的原因定位
- 字段大小写不匹配:目标JSON的字段为大写开头的
ID、Time,原命令中使用小写.id匹配,jq对键名严格区分大小写,完全无法命中目标字段 - 自定义变量未赋值:原命令中引用的
$ID是jq作用域内的变量,没有通过--arg参数传入值时,变量恒为null,无法匹配任何条目 - 匹配条件不完整:需求为同时满足ID、Time两个字段匹配才删除,原命令仅设置了ID单字段匹配规则
- 删除逻辑不兼容:
del(.[] | select(匹配条件))的写法在遍历删除时容易出现索引偏移问题,删除结果不稳定 - 无回写逻辑:默认jq仅将处理结果输出到终端,不会直接修改原文件
正确实现方案
核心过滤逻辑
相比容易出问题的del删除写法,直接用数组映射+筛选保留合规条目的逻辑更稳定,通过逻辑判断实现「删除同时满足ID和Time双匹配的条目」需求:
map(select( not ( .ID == "dimes-snapshot" and .Time == "2017-01-09T22:41:46.229000+00:00" ) ))
该逻辑会遍历数组所有条目,只排除同时命中两个匹配条件的元素,其余条目全部保留。
适配原文件回写的执行命令
通用兼容写法(适配所有jq版本)
采用临时文件中转的方式回写结果,避免jq处理异常时损坏原文件:
jq 'map(select(not (.ID == "dimes-snapshot" and .Time == "2017-01-09T22:41:46.229000+00:00")))' snapshot.json > snapshot.tmp && mv snapshot.tmp snapshot.json
高版本简化写法(jq 1.7及以上)
jq内置了原地修改参数--in-place,无需手动写临时文件中转:
jq --in-place 'map(select(not (.ID == "dimes-snapshot" and .Time == "2017-01-09T22:41:46.229000+00:00")))' snapshot.json
执行结果校验
命令执行完成后,snapshot.json内会移除目标匹配条目,剩余内容为:
[ { "ID": "delete-05032019", "Time": "2019-05-03T18:01:12.375000+00:00" }, { "ID": "dimes-snapshot-2", "Time": "2018-02-28T16:06:09.091000+00:00" } ]
内容的提问来源于stack exchange,提问作者Ebube
相关产品推荐
相关产品推荐

