Assume I have a json structure like:
{
"a" : 1,
"b" : 2,
"c" : 3
}
I want the same structure, but with only the first element:
{
"a" : 1
}
I don't know or care what the name of the key is. I just want the first one. (Bonus points for being able to grab an arbitrary nth one.)
How do I do this with jq
?
If I did know the name, this would be easy:
% echo '{"a":1,"b":2,"c":3}' | jq '{a}'
{
"a": 1
}
Which is a shortcut for:
% echo '{"a":1,"b":2,"c":3}' | jq '{a: .a}'
{
"a": 1
}
Working, but terrible, solution
In trying to come up with a bunch of examples for what I've tried that didn't work, I finally came up with this thing that does work:
% echo '{"a":1,"b":2,"c":3}' | jq '{(keys|first):.[(keys|first)]}'
{
"a": 1
}
but that cannot possibly be the best way to do this.
Notably, the "shortcut" doesn't work:
% 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
This also works, but is barely better, if not worse:
% echo '{"a":1,"b":2,"c":3}' | jq '(keys|first) as $i | {($i): .[$i]}'
{
"a": 1
}
(The "shortcut" doesn't work here, either.)
WTF?
Also, if I don't use parens around the $i
as the key, craziness happens that I don't understand at all:
% 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"
}
Other stuff that doesn't work
% 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
CodePudding user response:
Use to_entries
, from_entries
and an index of your choice.
In the single-element syntax you need to wrap it in an array
jq '[to_entries[0]] | from_entries'
In the range-syntax you need to additionally providde the to-index (which is one higher than the from-index if you want just 1 element):
jq 'to_entries[0:1] | from_entries'
Output:
{
"a": 1
}
CodePudding user response:
You can store the value to a variable:
$ echo '{"a":2,"b":3,"c":4}' | jq '(keys|first) as $f | {($f):.[$f]}'
{
"a": 2
}