You can use jq '.[] | .login, .id' to obtain each login followed by its id.
Use @tsv to generated tab-separated values as output:
Copyjq -r '[.user, .cmd] | @tsv' <yourfile
...emits, given your input file:
Copyalex echo '123'
john echo '456'
alex echo '789'
...though if you're filtering for only your user account, you can just print cmd directly, since the user value is known:
Copyjq -r 'select(.user == "alex") | .cmd'
When you write .user .cmd you are asking for the "cmd" field of the JSON object at .user. To obtain both the .user and .cmd values, you could use the "," operator:
Copy.user, .cmd
The above, however, will produce two lines. There are many options for emitting multiple values on a single line. You might wish to consider using string interpolation; or wrapping the values in square brackets and then using one of @csv, @tsv, or join/1; or using the -j command-line option.
This is all pretty clearly explained in the standard jq documentation (see e.g. https://stackoverflow.com/tags/jq/info), as is the use of select for making a selection.
Is it possible to output multiple values on a single line?
json - jq - print values in one line - Unix & Linux Stack Exchange
How do I select multiple keys for output?
How can I use jq to filter only certain fields of the original JSON into an CSV?
Use the "join", -j
$ jq -jr '.[]|"name:", " ",.name, "\n","groups:", (.grp[]|" ",.name),"\n"' test_json
name: cust1
groups: BA2 GA1 NA1 TR3 TS1
And with a place holder
$ jq -jr '.[]|"name:", " ",.name, "\n","groups:", (.grp//[{"name":"-"}]|.[]|" ",.name),"\n"' test_json
name: cust1
groups: -
$ jq -r '.[] |
[ "name:", .name ], [ "groups:", .grp[].name ]
| @tsv' file.json
name: cust1
groups: BA2 GA1 NA1 TR3 TS1
That is, give @tsv two arrays, one with the name, and one with the groups. Each array will become its own row.
In case the grp array may be empty and you'd like to insert a - instead:
$ jq -r '.[] |
[ "name:", .name ], [ "groups:", (.grp // [])[].name // "-" ]
| @tsv' file.json
name: cust1
groups: -
The operation x // y returns x unless x evaluates to null or false in which case it returns y.
This will also handle the case where grp is completely missing (not just an empty array).
Hello, I say this stack overflow anser with a simple jq command to convert a JSON to a csv file, but I need to improve it further.
Say I have the following JSON:
[
{
"name": "foo",
"env": "dev",
"version": "1.24"
},
{
"name": "bar",
"env": "staging",
"version": "1.21"
},
{
"name": "boo",
"env": "prod",
"version": "1.23"
},
{
"name": "far",
"env": "prod",
"version": "1.24"
}
]How does one create the CSV with only the "name" and "version" fields?
My current command is:
jq -r '(map(keys) | add | unique) as $cols | map(.[] | {name, version} as $row | $cols | map($row[.])) as $rows | $cols, $rows[] | @csv'This is not working. Can anyone provide some help?
Thanks!
While it is probably best to use a tool like the one peak suggested if your json isn't too complex you could use a second jq invocation to postprocess the output of the first. For example if your data is in data.json
$ jq -M . data.json | jq -MRsr 'gsub("\n +";"")|gsub("\n ]";"]")'
produces
{
"frameGrid": {
"size": [24,24],
"dimensions": [1,1],
"names": [["default"]]
}
}
As @jq170727 mentioned, postprocessing after a pretty-printing run of jq (e.g. jq .) is worth considering. In that vein, here is an awk script that might suffice:
#!/bin/bash
awk '
function ltrim(x) { sub(/^[ \t]*/, "", x); return x; }
s && NF > 1 && $NF == "[" { s=s $0; next}
s && NF == 1 && $1 == "]," { print s "],"; s=""; next}
s && NF == 1 && $1 == "[" { print s; s=$0; next}
s && NF == 1 && $1 == "{" { print s; print; s=""; next}
s && NF == 1 && $1 == "]" { print s $1; s=""; next}
s && NF == 1 && $1 == "}" { print s; s=$0; next}
s { s=s ltrim($0); next}
$NF == "[" { s=$0; next}
{print}
'
Examples
With the example input, the invocation:
jq . example.json | ./pp
produces:
{
"frameGrid": {
"size": [24,24],
"dimensions": [1,1],
"names": [
["default"]
]
}
}
The invocation:
jq -n '{a:[1,2,3,[1,2,3,4]],b:2,c:{d:[1,2,{e:[3,4]}]}}' | ./pp
produces:
{
"a": [1,2,3,
[1,2,3,4]
],
"b": 2,
"c": {
"d": [1,2,
{
"e": [3,4]
}
]
}
}
The easiest way in your example is to use String Interpolation along with the -r option. e.g.
echo '{ "fmep": { "foo": 112, "bar": 234324, "cat": 21343423 } }' | \
jq -r '.fmep| "\(.foo) \(.bar)"'
produces
112 234324
You may also want to consider putting the values in an array and using @tsv e.g.
echo '{ "fmep": { "foo": 112, "bar": 234324, "cat": 21343423 } }' | \
jq -r '.fmep | [.foo, .bar] | @tsv'
which produces tab-separated
112 234324
Here is the syntax using joined output (-j):
jq -j '.fmep | .foo, " ", .bar, "\n"' payload.json