jq以不同的方式对KEY和VALUES进行排序——我如何才能以相同的顺序枚举它们



我使用curl命令获得JSON格式的REST输出,如下所示

使用单独获取KEY名称

curl http://test.te:8080/testApp/app/version | jq '.version' | jq '. | keys'

输出:

"Archiver-Version",
"Build-Id",
"Build-Jdk",
"Build-Number",
"Build-Tag",
"Built-By"

使用单独获取VALUES

curl http://test.te.com:8080/testApp/app/version | jq '.version' | jq '.[]'

OUTPUT(注意值的顺序与关键字名称的顺序不一致;例如,第一个值"user@test.com"是关键字"Built-By"的值,而不是我所期望的第一个关键字"Archiver-Version"的值):

"user@test.com"
"1634d38"
"sandbox"
"02-03-2014-13:41"
"testApp"

我正在尝试将KEYS和VALUES分配给单独的数组,这样我就可以对它们进行迭代并以表格式显示它们。

但这两个命令的排序方式不同,我无法直接分配值和键。

是否要更改KEYS和VALUES的排序,使两者相同?

问题源于jq可能令人惊讶的默认行为:

  • keys按字母顺序枚举排序的键
  • .[]根据键的输入顺序枚举值[1]

换句话说:如果在一个过程中使用keys提取对象的,然后在另一个过程使用.[]提取其时,相应的输出元素可能不匹配。

jq v1.5引入了keys_unsorted/0功能,它实现了一个简单的解决方案:

# Sample input with unordered keys.
# Sorting the values results in the same order as sorting the keys,
# so the output order of values below implies the key enumeration order that was applied.
json='{ "c":3, "a":1, "b":2 }'

使用keys_unsorted/0:按输入顺序打印

$ echo "$json" | jq -r 'keys_unsorted[]'
c
a
b

按输入顺序打印[]总是这样做:

$ echo "$json" | jq -r '.[]'
3
1
2

Caveat:在v1.3版本之前,使用.[]导致没有保证的枚举顺序(使用了底层哈希表的密钥排序,这是一个实现细节);如果仍然必须使用v1.3,则可以使用下面显示的to_entries方法。


[v1.3+]to_entries/0,如用户2259432的有用答案中所用,也按输入顺序枚举属性

# Extract keys
$ echo "$json" | jq -r 'to_entries | map(.key)[]'
c
a
b
# Extract values
$ echo "$json" | jq -r 'to_entries | map(.value)[]'
3
1
2

注意事项在v1.5之前,to_entries/0按键顺序输出中的键值对

然而,由于to_entries/0可用于枚举键和值,因此它仍然是在并行键/值提取中生成稳定枚举顺序的可行解决方案,即使在v1.5之前的版本中也是如此。


[v1.3+]相比之下,如果您想中按键顺序进行枚举

使用keys/0:按字母顺序打印

$ echo "$json" | jq -r 'keys[]'
a
b
c

按字母顺序排序的键打印

$ echo "$json" | jq -r 'keys[] as $k | .[$k]'
1
2
3

关于-S/--sort-keys警告

此选项仅适用于整个对象,在输出上:

$ echo "$json" | jq -Sc '.'
{"a":1,"b":2,"c":3}  # Sorted by key

当您使用运算符或函数访问对象的内部时,它不适用:

$ echo "$json" | jq -S '.[]' # !! -S doesn't apply, because [] always uses input order
3
1
2

[1]在v1.5之前,没有特定的订单得到保证,但也产生了同样的问题

jq有一个对键进行排序的选项。看见http://stedolan.github.io/jq/manual/#Invokingjq

--sort-keys / -S:
Output the fields of each object with the keys in sorted order.

然而,当前发布的jq版本(1.3)还没有此增强,您需要通过其主分支的最新代码编译jq。看见http://stedolan.github.io/jq/download/,"从Linux或OS X上的源代码"部分。

有关此功能的完整历史记录和详细信息,请参阅第79期"按名称对对象成员排序的选项或函数"https://github.com/stedolan/jq/issues/79

您也可以

$ echo '{"a":0, "b":1}' | jq -c 'to_entries|map([.key, .value])|map(.[])'
["a",0,"b",1]

最新更新