I am trying to use jq to construct a hash in which a key name comes from a variable. Something like this:
jq --null-input --arg key foobar '{$key: "value"}'
This doesn't work, however, and gives the following error:
error: syntax error, unexpected '$'
{$key: "value"} 1 compile error
Use parentheses to evaluate $key early as in:
jq --null-input --arg key foobar '{($key): "value"}'
See also: Parentheses in JQ for .key
You can also use String interpolation in jq which is of the form "\(..)". Inside the string, you can put an expression inside parens after a backslash. Whatever the expression returns will be interpolated into the string.
You can do below. The contents of the variable key is expanded and returned as a string by the interpolation sequence.
jq --null-input --arg key foobar '{ "\($key)": "value"}'
Related
I'm trying to get jq to parse a JSON structure like:
{
"a" : 1,
"b" : 2,
"c" : "{\"id\":\"9ee ...\",\"parent\":\"abc...\"}\n"
}
That is, an element in the JSON is a string with escaped json.
So, I have something along the lines of
$ jq [.c] myFile.json | jq [.id]
But that crashes with jq: error: Cannot index string with string
This is because the output of .c is a string, not more JSON.
How do I get jq to parse this string?
My initial solution is to use sed to replace all the escape chars (\":\", \",\" and \") but that's messy, I assume there's a way built into jq to do this?
Thanks!
edit:
Also, the jq version available here is:
$ jq --version
jq version 1.3
I guess I could update it if required.
jq has the fromjson builtin for this:
jq '.c | fromjson | .id' myFile.json
fromjson was added in version 1.4.
You can use the raw output (-r) that will unescape characters:
jq -r .c myfile.json | jq .id
ADDENDUM: This has the advantage that it works in jq 1.3 and up; indeed, it should work in every version of jq that has the -r option.
Motivation: you want to parse JSON string - you want to escape a JSON object that's wrapped with quotes and represented as a String buffer, and convert it to a valid JSON object. For example:
some JSON unescaped string :
"{\"name\":\"John Doe\",\"position\":\"developer\"}"
the expected result ( a JSON object ):
{"name":"John Doe","position":"developer"}
Solution: In order to escape a JSON string and convert it into a valid JSON object use the sed tool in command line and use regex expressions to remove/replace specific characters:
cat current_json.txt | sed -e 's/\\\"/\"/g' -e 's/^.//g' -e 's/.$//g'
s/\\\"/\"/g replacing all backslashes and quotes ( \" ) into quotes only (")
s/^.//g replacing the first character in the stream to none character
s/.$//g replacing the last character in the stream to none character
cat explorer/connection-profile/test-network.json | jq ".organizations.Org1MSP.adminPrivateKey.path |= 44ab"
jq: error: syntax error, unexpected IDENT, expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
.organizations.Org1MSP.adminPrivateKey.path|=44ab
jq: 1 compile error
but it works fine with
cat explorer/connection-profile/test-network.json | jq ".organizations.Org1MSP.adminPrivateKey.path |= 44"
Why?
Actually I am trying to use
cat explorer/connection-profile/test-network.json | jq ".organizations.Org1MSP.adminPrivateKey.path |= ${PRIV_KEY}"
where the ${PRIV_KEY} is 44ab..._sk
You can assign a string to a variable that can be used inside a jq filter:
PRIV_KEY="44ab..._sk"
jq --arg path "$PRIV_KEY" '.organizations.Org1MSP.adminPrivateKey.path |= $path' explorer/connection-profile/test-network.json
This method is safer than trying to embed an expanded shell variable directly in the filter string because jq will properly handle arbitrary values instead of choking on things like quotes (Or their absence).
Note that jq takes filenames as arguments after the filter expression; no need for cat here (Unless that's standing in for curl or something, of course, and you're not using an existing file)
did you try this , i fixed the same error by setting the expression between '' and the values between ""
cat explorer/connection-profile/test-network.json | jq '.organizations.Org1MSP.adminPrivateKey.path |= "44ab"'
I'm seeing a is not defined at <top-level> when calling jq like so:
jq ".Changes[0].ResourceRecordSet.Name = word-is-here.domain.com" someFile.json
The error repeats for each word separated by a dash in the second side of the replacement. The full error is like
jq: error: word/0 is not defined at <top-level>, line 1:
.Changes[0].ResourceRecordSet.Name = word-is-here.domain.com
I've tried escaping quotes in many different ways but that didn't help. (what I mean by this is doing "'"'" weird stuff, I'm still learning bash so I'm just trowing stuff at the wall until it sticks)
EDIT:
So I'm trying to run this in a bash script, and both side of the = signs are variables such as jq --arg value "$value" --arg key "$key" '$key = $value' "$path" (what I tried after a suggestion)
and got the error:
Invalid path expression with result ".Changes[0].ResourceRecor...
The json I'm using is as such:
{
"Changes": [
{
"Action": "do something",
"ResourceRecordSet": {
"Name": "some name here to replace",
...
}
}
]
}
jq '.Changes[0].ResourceRecordSet.Name = "word-is-here.domain.com"' file.json
Quote the string you are assigning. Or pass it to jq via an argument:
jq --arg foo 'words-here' '.Changes[0].ResourceRecordSet.Name = $foo' file.json
For passing the path to the key you want as an argument, a suggestion from https://github.com/stedolan/jq/issues/1493 might work:
jq --argjson path '["Changes",0,"ResourceRecordSet","Name"]' \
--arg val 'word-is-here.domain.com' \
'getpath($path) = $val' file.json
The problem (or at least the obvious problem) here is evidently the string: word-is-here.domain.com, since jq is interpreting the dash ("-") as an operation ("minus").
Unfortunately, since you haven't given us many clues, it's not completely clear what specifically needs to be changed, but a reasonable guess is that word-is-here.domain.com is intended as a fixed string. If so, you would have to present it as a JSON string. So in a bash or bash-like environment, you could write:
jq '.Changes[0].ResourceRecordSet.Name = "word-is-here.domain.com"' someFile.json
Specifying the LHS path via a shell variable
If the LHS path must be specified by a shell variable, it should if possible be passed in as a JSON array, e.g. using the --argjson command-line option; one can then use an expression of the form setpath($path; $value) to update the path.
If for some reason a solution allowing the LHS to be specified as a jq path is preferred, then shell string-interpolation could be used, though as with any such interpolation, this should be done with care.
I need to get a specific value from a json file using jq in a bash script (busybox). The json file looks like this:
{
"example.com": {
"backend": "1.3.7"
}
}
In my script there are two variables: project and app - as there are of course multiple projects and applications. I need to use these variable values to get the version value. In this example project is "example.com" and app is "backend"
I tried this
jq --arg p "$project" --arg a "$app" '.[$p].[$a]' file.json
But I do get the error
jq: error: syntax error, unexpected '[', expecting FORMAT or QQSTRING_START (Unix shell quoting issues?) at <top-level>, line 1:
.[$p].[$a]
jq: 1 compile error
You may use it like this:
jq -r --arg p "$project" --arg a "$app" '.[$p][$a]' file.json
or else:
jq -r --arg p "$project" --arg a "$app" '.[$p] | .[$a]' file.json
1.3.7
How to make jq treat an input argument as numeric instead of string? In the following example, CURR_INDEX is a Bash variable which has array index value that I want to extract.
jq --arg ARG1 $CURR_INDEX '.[$ARG1].patchSets' inputfile.json
I get the following error:
jq: error: Cannot index array with string
I tried the workaround of using bash eval but some jq filters do not work properly in eval statements.
You can convert it to a number, like this:
jq --arg ARG1 1 '.[$ARG1|tonumber]' <<< '["foo". "bar"]'
"bar"
--arg always binds the value as a string. You can use --argjson (introduced in version 1.5) to treat the argument as a json-encoded value instead.
jq --argjson ARG1 $CURR_INDEX '.[$ARG1].patchSets' inputfile.json
To see it in action, you can reproduce your original error:
$ jq --argjson ARG1 '"1"' '.[$ARG1]' <<< '["foo", "bar"]'
jq: error (at <stdin>:1): Cannot index array with string "1"
then correct it:
$ jq --argjson ARG1 1 '.[$ARG1]' <<< '["foo", "bar"]'
"bar"