bash 删除所有空值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39500608/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Remove all null values
提问by Ela
I am trying to remove null values from a json object using jq. I found this issueon their github and so now I'm trying to remove them with del
.
I have this:
我正在尝试使用 jq 从 json 对象中删除空值。我在他们的 github 上发现了这个问题,所以现在我试图用del
. 我有这个:
'{ id: $customerId, name, phones: ([{ original: .phone },
{ original: .otherPhone}]), email} | del(. | nulls)'
This doesn't seem to do anything. However if I replace nulls
with .phones
it does remove the phone numbers.
这似乎没有任何作用。但是,如果我nulls
用.phones
它替换确实会删除电话号码。
回答by peak
The following illustrates how to remove all the null-valued keys from a JSON object:
下面说明了如何从 JSON 对象中删除所有空值键:
jq -n '{"a":1, "b": null, "c": null} | with_entries( select( .value != null ) )'
{
"a": 1
}
Alternatively, paths/0
can be used as follows:
或者,paths/0
可以按如下方式使用:
. as $o | [paths[] | {(.) : ($o[.])} ] | add
By the way, del/1
can also be used to achieve the same result, e.g. using this filter:
顺便说一句,del/1
也可以用来达到相同的结果,例如使用这个过滤器:
reduce keys[] as $k (.; if .[$k] == null then del(.[$k]) else . end)
Or less obviously, but more succinctly:
或者不那么明显,但更简洁:
del( .[ (keys - [paths[]])[] ] )
And for the record, here are two ways to use delpaths/1
:
为了记录,这里有两种使用方法delpaths/1
:
jq -n '{"a":1, "b": null, "c": null, "d":2} as $o
| $o
| delpaths( [ keys[] | select( $o[.] == null ) ] | map( [.]) )'
$ jq -n '{"a":1, "b": null, "c": null, "d":2}
| [delpaths((keys - paths) | map([.])) ] | add'
In both these last two cases, the output is the same: { "a": 1, "d": 2 }
在后两种情况下,输出是相同的:{ "a": 1, "d": 2 }
回答by Jeff Mercado
That's not what del/1
was meant to be used for. Given an object as input, if you wanted to remove the .phones
property, you'd do:
这不是del/1
用来做什么的。给定一个对象作为输入,如果您想删除该.phones
属性,您可以这样做:
del(.phones)
In other words, the parameter to del
is the path to the property you wish to remove.
换句话说,参数 todel
是您要删除的属性的路径。
If you wanted to use this, you would have to figure out all the paths to null
values and pass it in to this. That would be more of a hassle though.
如果您想使用它,则必须找出所有null
值的路径并将其传递给 this。不过那会比较麻烦。
Streaming the input in could make this task even simpler.
流式输入可以使这项任务更加简单。
fromstream(tostream | select(length == 1 or .[1] != null))
Otherwise for a more straightforward approach, you'll have to walk through the object tree to find null
values. If found, filter it out. Using walk/1
, your filter could be applied recursively to exclude the null
values.
否则,对于更直接的方法,您必须遍历对象树以查找null
值。如果找到,将其过滤掉。使用walk/1
,您的过滤器可以递归应用以排除null
值。
walk(
(objects | with_entries(select(.value != null)))
// (arrays | map(select(. != null)))
// values
)
So if you had this for input:
所以如果你有这个输入:
{
"foo": null,
"bar": "bar",
"biz": [1,2,3,4,null],
"baz": {
"a": 1,
"b": null,
"c": ["a","b","c","null",32,null]
}
}
This filter would yield:
这个过滤器会产生:
{
"bar": "bar",
"baz": {
"a": 1,
"c": ["a","b","c","null",32]
},
"biz": [1,2,3,4]
}
回答by jsxt
[WARNING: the definition of walk/1
given in this response is problematic, not least for the reason given in the first comment; note also that jq 1.6 defines walk/1
differently.]
[警告:walk/1
此回复中给出的定义是有问题的,尤其是第一条评论中给出的原因;还要注意 jq 1.6 的定义walk/1
不同。]
I am adding the new answer to emphasize the extended version of the script by @jeff-mercado. My version of the script assumes the empty values are as follows:
我正在添加新答案以强调@jeff-mercado 的脚本的扩展版本。我的脚本版本假设空值如下:
null
;[]
- empty arrays;{}
- empty objects.
null
;[]
- 空数组;{}
- 空物体。
Removing of empty arrays and objects was borrowed from here https://stackoverflow.com/a/26196653/3627676.
删除空数组和对象是从这里借用的https://stackoverflow.com/a/26196653/3627676。
def walk(f):
. as $in |
if type == "object" then
reduce keys[] as $key
( {}; . + { ($key): ( $in[$key] | walk(f) ) } ) | f
elif type == "array" then
select(length > 0) | map( walk(f) ) | f
else
f
end;
walk(
if type == "object" then
with_entries(select( .value != null and .value != {} and .value != [] ))
elif type == "array" then
map(select( . != null and . != {} and .!= [] ))
else
.
end
)
回答by L S
[WARNING: the response below has several problems, not least those arising from the fact that 0|length
is 0.]
[警告:下面的响应有几个问题,尤其是那些由0|length
0引起的问题。]
Elaborating on an earlier answer, in addition to removing properties with null
values, it's often helpful to remove JSON properties with empty array or object values (i.e., []
or {}
), too.
详细说明较早的答案,除了删除带有null
值的属性之外,删除带有空数组或对象值(即,[]
or {}
)的JSON 属性通常也很有帮助。
?? — jq's
walk()
function (walk/1
) makes this easy.walk()
will be available in a future version of jq (>jq-1.5
), but its definitioncan be added to current filters.
?? — jq 的
walk()
函数 (walk/1
) 使这变得容易。walk()
将在 jq (>jq-1.5
)的未来版本中可用,但它的定义可以添加到当前过滤器中。
The condition to pass to walk()
for removing nulls and empty structures is:
要传递给walk()
删除空值和空结构的条件是:
walk(
if type == "object" then with_entries(select(.value|length > 0))
elif type == "array" then map(select(length > 0))
else .
end
)
Given this JSON input:
鉴于此 JSON 输入:
{
"notNullA": "notNullA",
"nullA": null,
"objectA": {
"notNullB": "notNullB",
"nullB": null,
"objectB": {
"notNullC": "notNullC",
"nullC": null
},
"emptyObjectB": {},
"arrayB": [
"b"
],
"emptyBrrayB": []
},
"emptyObjectA": {},
"arrayA": [
"a"
],
"emptyArrayA": []
}
Using this function gives the result:
使用这个函数给出了结果:
{
"notNullA": "notNullA",
"objectA": {
"notNullB": "notNullB",
"objectB": {
"notNullC": "notNullC"
},
"arrayB": [
"b"
]
},
"arrayA": [
"a"
]
}
回答by peak
Elsewhere on this page, some interest has been expressed in using jq to eliminate recursively occurrences of [] and {} as well as null.
在本页的其他地方,有人对使用 jq 消除递归出现的 [] 和 {} 以及 null 表示了一些兴趣。
Although it is possible to use the built-in definition of walk/1
to do
this, it is a bit tricky to do so correctly. Here therefore is a variant version
of walk/1
which makes it trivial to do so:
尽管可以使用 的内置定义walk/1
来执行此操作,但正确执行此操作有点棘手。因此,walk/1
这是一个变体版本,它使这样做变得微不足道:
def traverse(f):
if type == "object" then map_values(traverse(f)) | f
elif type == "array" then map( traverse(f) ) | f
else f
end;
In order to make it easy to modify the criterion for removing elements, we define:
为了方便修改移除元素的标准,我们定义:
def isempty: .==null or ((type|(.=="array" or .=="object")) and length==0);
The solution is now simply:
现在的解决方案很简单:
traverse(select(isempty|not))
回答by Caleb
All the other answers to date here are workarounds for old versions of jq
, and it isn't clear how do do this simply in the latest released version. In JQ 1.6 or newer this will do the job to remove nulls recursively:
迄今为止,这里的所有其他答案都是旧版本的解决方法jq
,目前尚不清楚如何在最新发布的版本中简单地做到这一点。在 JQ 1.6 或更新版本中,这将完成递归删除空值的工作:
$ jq 'walk( if type == "object" then with_entries(select(.value != null)) else . end)' input.json
Sourced from this commenton the issue where adding the walk()
function was discussed upstream.
源自有关上游讨论添加功能的问题的评论walk()
。