使用 jq 一次删除多个键
Posted
技术标签:
【中文标题】使用 jq 一次删除多个键【英文标题】:Deleting multiple keys at once with jq 【发布时间】:2016-07-13 15:22:37 【问题描述】:我需要从一些 JSON 中一次删除多个键(使用jq
),我正在尝试了解是否有比每次调用 map 和 del 更好的方法。这是我的输入数据:
test.json
[
"label": "US : USA : English",
"Country": "USA",
"region": "US",
"Language": "English",
"locale": "en",
"currency": "USD",
"number": "USD"
,
"label": "AU : Australia : English",
"Country": "Australia",
"region": "AU",
"Language": "English",
"locale": "en",
"currency": "AUD",
"number": "AUD"
,
"label": "CA : Canada : English",
"Country": "Canada",
"region": "CA",
"Language": "English",
"locale": "en",
"currency": "CAD",
"number": "CAD"
]
对于每个项目,我想删除数字、语言和国家/地区键。我可以用这个命令做到这一点:
$ cat test.json | jq 'map(del(.Country)) | map(del(.number)) | map(del(.Language))'
效果很好,我得到了想要的输出:
[
"label": "US : USA : English",
"region": "US",
"locale": "en",
"currency": "USD"
,
"label": "AU : Australia : English",
"region": "AU",
"locale": "en",
"currency": "AUD"
,
"label": "CA : Canada : English",
"region": "CA",
"locale": "en",
"currency": "CAD"
]
但是,我想了解是否有 jq
指定要删除的多个标签的方式,所以我不必有多个 map(del())
指令?
【问题讨论】:
【参考方案1】:您可以提供一个流要删除的路径:
$ cat test.json | jq 'map(del(.Country, .number, .Language))'
另外,考虑到,您可能更愿意将您想要的键列入白名单,而不是将特定键列入黑名单:
$ cat test.json | jq 'map(label, region, locale, currency)'
【讨论】:
【参考方案2】:没有必要同时使用map
和del
。
您可以将多个路径传递给del
,以逗号分隔。
这是一个使用“点式”路径表示法的解决方案:
jq 'del( .[] .Country, .[] .number, .[] .Language )' test.json
不需要引号(您可能会觉得它更易读)
不对路径进行分组(要求您在每个路径中重新键入一次.[]
)
这是一个使用“数组样式”路径表示法的示例,它允许您将具有公共前缀的路径组合起来,如下所示:
jq 'del( .[] ["Country", "number", "Language"] )' test.json
在“最后一个共同祖先”下组合子路径(在本例中是***列表迭代器.[]
)
peak 的回答使用了map
和delpaths
,不过您似乎也可以单独使用delpaths
:
jq '[.[] | delpaths( [["Country"], ["number"], ["Language"]] )]' test.json
需要引号和单例数组的数组
要求您将其放回列表中(带有开始和结束方括号)
总的来说,为了简洁起见,我会选择数组样式的表示法,但知道做同一件事的多种方法总是好的。
【讨论】:
【参考方案3】:Louis 在其answer 中提到的“数组样式”和“点样式”表示法之间的更好折衷。
del(.[] | .Country, .number, .Language)
jqplay
此表单还可用于从嵌套对象中删除键列表(参见 russholio 的 answer):
del(.a | .d, .e)
暗示你也可以选择一个索引来删除键:
del(.[1] | .Country, .number, .Language)
或多个:
del(.[2,3,4] | .Country,.number,.Language)
您可以使用range()
函数删除范围(切片表示法不起作用):
del(.[range(2;5)] | .Country,.number,.Language) # same as targetting indices 2,3,4
一些旁注:
map(del(.Country,.number,.Language))
# Is by definition equivalent to
[.[] | del(.Country,.number,.Language)]
如果密钥包含特殊字符或以数字开头,则需要用双引号将其括起来,如下所示:
."foo$"
,否则为.["foo$"]
。
【讨论】:
【参考方案4】:除了@user3899165的回答,我发现要从“子对象”中删除一个键列表
example.json
"a":
"b": "hello",
"c": "world",
"d": "here's",
"e": "the"
,
"f":
"g": "song",
"h": "that",
"i": "I'm",
"j": "singing"
$ jq 'del(.a["d", "e"])' example.json
【讨论】:
【参考方案5】:delpaths
也是值得了解的,也许没有那么神秘:
map( delpaths( [["Country"], ["number"], ["Language"]] ))
由于delpaths
的参数只是 JSON,因此这种方法对于程序删除特别有用,例如如果键名可以作为 JSON 字符串使用。
【讨论】:
delpaths
将设置为null
在提供的路径表达式中找到的键的值,它不会按照此处的要求删除键。
@LouisMaddox - 我已经使用 jq 1.3、1.4、1.5 和 1.6 测试了上面给出的程序,在所有情况下,结果都是删除了密钥。如果您对最近的投票负责,请不要忘记将其删除。谢谢。
我仍然认为这是一个不受欢迎的答案:OP 表示“我正在尝试了解是否有比每次调用 map 和 del 更好的方法”。有:使用单个del
调用,这也将路径名周围的方括号数量减少到2,而不是8:jq 'del( .[] ["Country", "number", "Language"] )' test.json
。您的答案有效,但我发现它是潜在的混淆来源和潜在的静默错误(因为 delpaths
不会删除密钥,而是在保留密钥时设置为 null
)。这在过去一直困扰着我,所以我推荐使用更简单的del
来代替。
(a) 没有声称使用 delpaths 是最好的方法,只是说它是 Q 中要求的更好的方法。(b) 即使指向不存在的键的路径是包括在内,未添加密钥,因此我不理解您对“保留密钥”的担忧。
我昨天刚被这个咬了一口,因此被否决了,就这么简单:-) 没有冒犯的意思。除非您编辑答案,否则 *** 不会让我取消投票。我对“保留密钥”的担忧是指在不使用 map
的情况下使用 delpaths
,在这种情况下,它将将该密钥的值设置为 null
,但保留密钥本身。以上是关于使用 jq 一次删除多个键的主要内容,如果未能解决你的问题,请参考以下文章
如何一次从CloudFormation中删除多个全局二级索引?