1

I often find myself wanting to parse json with the jq command, but one of the values inside the json is an escaped string of json.

e.g. if I generate data with python like this:

import json
inner = {'a': 'b'}
outer = {'x': json.dumps(inner)}
json.dumps(outer)

I get:

{"x": "{\"a\": \"b\"}"}

How do I get "b" using the jq command?

$ echo '{"x": "{\"a\": \"b\"}"}' | jq .x
"{\"a\": \"b\"}"

Ok, that's the first step. But the result isn't a json dictionary. It's a string that needs to be escaped and parsed into json.

jq .x.a throws an error: jq: error (at <stdin>:1): Cannot index string with string "a"

Is there an argument I can add to jq to chain together two jq steps? Or is there another command I can use instead?

e.g.

echo '{"x": "{\"a\": \"b\"}"}' | jq .x | jq --some-argument .a

or

echo '{"x": "{\"a\": \"b\"}"}' | jq .x | something-else | jq .a
falsePockets
  • 3,826
  • 4
  • 18
  • 37

1 Answers1

2

The following does the trick:

echo '{"x": "{\"a\": \"b\"}"}' | jq -r .x | jq .a

Here the -r step ensures that the output is raw strings, not JSON texts. Therefore:

"{\"a\": \"b\"}" -> {"a": "b"},

where this "raw string" can subsequently be taken as JSON input for jq .a, returning "b" (or b when used with -r flag).

EDIT: Calling jq twice is not ideal (thanks @peak), the previous command can be combined in this oneliner

| jq -r '.x|fromjson.a'
Casper Dijkstra
  • 1,615
  • 10
  • 37
  • Yes I was aware that this solution was not ideal yet, wanted to check today how it could be improved. Thanks! Your solution doesn't work yet though, but i'm sure `fromstring` can be useful – Casper Dijkstra Nov 03 '20 at 07:55
  • In 1.6 i'm getting `jjq: error: fromstring/0 is not defined at , line 1: .x|fromstring.a jq: 1 compile error` – Casper Dijkstra Nov 03 '20 at 08:11
  • 1
    You're right. I meant: Avoid calling jq twice by using `fromjson`, e.g. `jq -r '.x|fromjson.a'` – peak Nov 03 '20 at 08:20