Search code examples
jsonshellcommand-linejqtext-processing

how to use jq to print one-line per root-level object key?


I would like to compress the space for a json file by printing in compact mode (-c) but I want to add a new line after each root-level object.

for example, for the below object

{
  "a": {
    "a1": 1,
    "a2": [
      null
    ]
  },
  "b": {
    "b1": "test"
  },
  "c": [
    1,
    2,
    3
  ]
}

I would like to print it as

{
"a":{"a1":1,"a2":[null]},
"b":{"b1":"test"},
"c":[1,2,3]
}

i.e., one root-level object per line (adding the start/end brackets)

I got as far as printing each item in one line using

echo '{"a":{"a1":1, "a2":[null]}, "b": {"b1":"test"}, "c": [1,2,3]}' | jq -c -r '. | to_entries | .[] | "\"\(.key)\": \(.value)"'

"a": {"a1":1,"a2":[null]}
"b": {"b1":"test"}
"c": [1,2,3]

but I am not able to form a single valid JSON object.

can someone offer some suggestions? thanks

Update:

I managed to achieve the goal using a combination of jq and perl

echo '{"a":{"a1":1, "a2":[null]}, "b": {"b1":"test"}, "c": [1,2,3]}' | jq -c -r '. | to_entries | .[] | @json "\(.key): \(.value)"' | perl -pe 's/$/,/m if !eof' | perl -p0e 's/^/{\n/' | perl -p0e 's/$/\n}/'

Solution

  • You have very limited options how jq does pretty-printing. Your best bet is to write your own. Here's a very manual approach using to_entries and @json

    jq -r '
      "{", ([to_entries[] | @json "\(.key):\(.value)"] | .[:-1][] += ",")[], "}"
    '
    
    {
    "a":{"a1":1,"a2":[null]},
    "b":{"b1":"test"},
    "c":[1,2,3]
    }
    

    Demo