使用 jq 去除对象的第一个元素以外的所有元素
strip all but the first element of an object with jq
假设我有一个 json 结构,例如:
{
"a" : 1,
"b" : 2,
"c" : 3
}
我想要相同的结构,但只有第一个元素:
{
"a" : 1
}
我不知道也不关心密钥的名称是什么。我只想要第一个(能够获得任意第 n 个奖励积分。)
如何使用 jq
执行此操作?
如果我确实知道这个名字,这就很容易了:
% echo '{"a":1,"b":2,"c":3}' | jq '{a}'
{
"a": 1
}
这是一个快捷方式:
% echo '{"a":1,"b":2,"c":3}' | jq '{a: .a}'
{
"a": 1
}
有效但糟糕的解决方案
在尝试为我尝试过但没有用的东西想出一堆例子时,我终于想出了一个有用的东西:
% echo '{"a":1,"b":2,"c":3}' | jq '{(keys|first):.[(keys|first)]}'
{
"a": 1
}
但这不可能是最好的方法。
值得注意的是,“快捷方式”不起作用:
% echo '{"a":1,"b":2,"c":3}' | jq '{(keys|first)}'
jq: error: syntax error, unexpected '}', expecting ':' (Unix shell quoting issues?) at <top-level>, line 1:
{(keys|first)}
jq: 1 compile error
这也有效,但也好不了多少,甚至更糟:
% echo '{"a":1,"b":2,"c":3}' | jq '(keys|first) as $i | {($i): .[$i]}'
{
"a": 1
}
(“快捷方式”在这里也不起作用。)
卧槽?
此外,如果我不在 $i
周围使用括号作为键,就会发生我根本不理解的疯狂情况:
% echo '{"a":1,"b":2,"c":3}' | jq '(keys|first) as $i | {$i: .[$i]}'
jq: error: syntax error, unexpected ':', expecting '}' (Unix shell quoting issues?) at <top-level>, line 1:
(keys|first) as $i | {$i: .[$i]}
jq: error: May need parentheses around object key expression at <top-level>, line 1:
(keys|first) as $i | {$i: .[$i]}
jq: 2 compile errors
% echo '{"a":1,"b":2,"c":3}' | jq '(keys|first) as $i | {$i}'
{
"i": "a"
}
其他不起作用的东西
% echo '{"a":1,"b":2,"c":3}' | jq 'first'
jq: error (at <stdin>:1): Cannot index object with number
% echo '{"a":1,"b":2,"c":3}' | jq 'first(.)'
{
"a": 1,
"b": 2,
"c": 3
}
% echo '{"a":1,"b":2,"c":3}' | jq 'first(.[])'
1
使用 to_entries
、from_entries
和您选择的索引。
在 single-element 语法中,您需要将其包装在一个数组中
jq '[to_entries[0]] | from_entries'
在 range-syntax 中,您需要额外提供 to-index(如果您只需要 1 个元素,则比 from-index 高一个):
jq 'to_entries[0:1] | from_entries'
输出:
{
"a": 1
}
在评论中你说
I was just hoping for something more like .[0]
如果您不喜欢其他解决方案的管道,那么使用字符串插值怎么样:
jq '{"\(keys_unsorted[0])"}'
{
"a": 1
}
请注意,您最初的所有尝试都使用了 keys
,它以 字母顺序 提供密钥。对于示例数据,这没有什么区别,但我假设您实际上是在寻找 表示顺序 中的第一个键,您需要使用 keys_unsorted
。
如果我错了,那么我的答案翻译成 {"\(keys[0])"}
应该也能正常工作。
您可以使用 jq 的流解析器,如果输入对象很大,这实际上可能有意义。
# counting from 1
# e.g. 2 | nthRun(1,2,2,3; .) #=> 2,2
def nthRun(s; f):
. as $n
| label $out
| foreach s as $x (null;
if . == null then [1, ($x|f)]
elif .[1] == ($x|f) then .
else .[0] += 1 | .[1] = ($x|f)
end;
if .[0] == $n then $x
elif .[0] > $n then break $out
else empty
end);
fromstream(1|nthRun(inputs; .[0][0]), [[null]] )
调用示例:
jq -nc --stream -f program.jq input.json
郑重声明,假设第一个键的值是原子的,您可以简单地写成:
jq -nc --stream 'fromstream(input, [[null]])'
同样的nthRun
当然也可以用同样的方式访问n-thkey-value对。更一般地,它可以在不使用 --stream 选项的情况下使用,例如:
def firstKeyValue:
fromstream(1|nthRun(tostream),[[null]]);
假设我有一个 json 结构,例如:
{
"a" : 1,
"b" : 2,
"c" : 3
}
我想要相同的结构,但只有第一个元素:
{
"a" : 1
}
我不知道也不关心密钥的名称是什么。我只想要第一个(能够获得任意第 n 个奖励积分。)
如何使用 jq
执行此操作?
如果我确实知道这个名字,这就很容易了:
% echo '{"a":1,"b":2,"c":3}' | jq '{a}'
{
"a": 1
}
这是一个快捷方式:
% echo '{"a":1,"b":2,"c":3}' | jq '{a: .a}'
{
"a": 1
}
有效但糟糕的解决方案
在尝试为我尝试过但没有用的东西想出一堆例子时,我终于想出了一个有用的东西:
% echo '{"a":1,"b":2,"c":3}' | jq '{(keys|first):.[(keys|first)]}'
{
"a": 1
}
但这不可能是最好的方法。
值得注意的是,“快捷方式”不起作用:
% echo '{"a":1,"b":2,"c":3}' | jq '{(keys|first)}'
jq: error: syntax error, unexpected '}', expecting ':' (Unix shell quoting issues?) at <top-level>, line 1:
{(keys|first)}
jq: 1 compile error
这也有效,但也好不了多少,甚至更糟:
% echo '{"a":1,"b":2,"c":3}' | jq '(keys|first) as $i | {($i): .[$i]}'
{
"a": 1
}
(“快捷方式”在这里也不起作用。)
卧槽?
此外,如果我不在 $i
周围使用括号作为键,就会发生我根本不理解的疯狂情况:
% echo '{"a":1,"b":2,"c":3}' | jq '(keys|first) as $i | {$i: .[$i]}'
jq: error: syntax error, unexpected ':', expecting '}' (Unix shell quoting issues?) at <top-level>, line 1:
(keys|first) as $i | {$i: .[$i]}
jq: error: May need parentheses around object key expression at <top-level>, line 1:
(keys|first) as $i | {$i: .[$i]}
jq: 2 compile errors
% echo '{"a":1,"b":2,"c":3}' | jq '(keys|first) as $i | {$i}'
{
"i": "a"
}
其他不起作用的东西
% echo '{"a":1,"b":2,"c":3}' | jq 'first'
jq: error (at <stdin>:1): Cannot index object with number
% echo '{"a":1,"b":2,"c":3}' | jq 'first(.)'
{
"a": 1,
"b": 2,
"c": 3
}
% echo '{"a":1,"b":2,"c":3}' | jq 'first(.[])'
1
使用 to_entries
、from_entries
和您选择的索引。
在 single-element 语法中,您需要将其包装在一个数组中
jq '[to_entries[0]] | from_entries'
在 range-syntax 中,您需要额外提供 to-index(如果您只需要 1 个元素,则比 from-index 高一个):
jq 'to_entries[0:1] | from_entries'
输出:
{
"a": 1
}
在评论中你说
I was just hoping for something more like
.[0]
如果您不喜欢其他解决方案的管道,那么使用字符串插值怎么样:
jq '{"\(keys_unsorted[0])"}'
{
"a": 1
}
请注意,您最初的所有尝试都使用了 keys
,它以 字母顺序 提供密钥。对于示例数据,这没有什么区别,但我假设您实际上是在寻找 表示顺序 中的第一个键,您需要使用 keys_unsorted
。
如果我错了,那么我的答案翻译成 {"\(keys[0])"}
应该也能正常工作。
您可以使用 jq 的流解析器,如果输入对象很大,这实际上可能有意义。
# counting from 1
# e.g. 2 | nthRun(1,2,2,3; .) #=> 2,2
def nthRun(s; f):
. as $n
| label $out
| foreach s as $x (null;
if . == null then [1, ($x|f)]
elif .[1] == ($x|f) then .
else .[0] += 1 | .[1] = ($x|f)
end;
if .[0] == $n then $x
elif .[0] > $n then break $out
else empty
end);
fromstream(1|nthRun(inputs; .[0][0]), [[null]] )
调用示例:
jq -nc --stream -f program.jq input.json
郑重声明,假设第一个键的值是原子的,您可以简单地写成:
jq -nc --stream 'fromstream(input, [[null]])'
同样的nthRun
当然也可以用同样的方式访问n-thkey-value对。更一般地,它可以在不使用 --stream 选项的情况下使用,例如:
def firstKeyValue:
fromstream(1|nthRun(tostream),[[null]]);