I have an output from a process that looks like this:
{
"v1": "x0482030ssj09645j34"
}
I need to parse this output in order to extract x0482030ssj09645j34.
Any help is appreciated. Thanks!
jq is a handy JSON parser. In this case, you can do
your_process | jq -r '.v1'
to output just that value
Related
I am trying to copy certain key:value pairs from a json file to normal text file using jq within a bash script. I am doing:
#!/usr/bin/env bash
TestConfig="[...]/config_test.json"
#create new empty file if it doesn't exist
echo -n "" > test_sample.txt
echo "X=$(jq -r .abc $TestConfig '.' > test_sample.txt)"
echo "Y=$(jq -r .xyz $TestConfig '.' > test_sample.txt)"
But this copies only "values" (only values of .abc and .xyz) to test_sample.txt. But I am expecting:
cat test_sample.txt
X=test1
Y=test2
The config_test.json is:
{
"abc": "test1",
"xyz": "test2"
}
Can anyone please let me know what needs to be changed to have expected outcome? The .json file is quite big and I am extracting more key:value pairs from it. Hence any looping way to reduce jq operation time would be helpful.
Thanks in advance.
P.S: Please let me know if any info is missing.
If I understood correctly, you want to convert a JSON object's fields to raw text, following a key=value structure.
Use to_entries to decompose the object, iterate over its items with [], and output a formatted string using the .key and the .value. Make sure the output is raw text using -r:
jq -r 'to_entries[] | "\(.key)=\(.value)"' config_test.json > test_sample.txt
abc=test1
xyz=test2
Demo
In my bash script, when I run the following jq against my curl result:
curl -u someKey:someSecret someURL 2>/dev/null | jq -r '.schema' | jq -r -c '.fields'
I get back a JSON array as follows:
[{"name":"id","type":"int","doc":"Documentation for the id field."},{"name":"test_string","type":"string","doc":"Documentation for the test_string field"}]
My goal is to do a call with jq applied to return the following (given the example above):
{"id":1234567890,"test_string":"xxxxxxxxxx"}
NB: I am trying to automatically generate templated values that match the "schema" JSON shown above.
So just to clarify, that is:
all array objects (there could be more than 2 shown above) returned in a single comma-delimited row
doc fields are ignored
the values for "name" (including their surrounding double-quotes) are concatenated with either:
:1234567890 ...when the "type" for that object is "int"
":xxxxxxxxxx" ...when the "type" for that object is "string"
NB: these will be the only types we ever get for now
Can someone show me how I can expand upon my initial jq to return this?
NB: I tried working down the following path but am failing beyond this...
curl -u someKey:someSecret someURL 2>/dev/null | jq -r '.schema' | jq -r -c '.fields' | "\(.name):xxxxxxxxxxx"'
If it's not possible in pure JQ (my preference) I'm also happy for a solution that mixes in a bit of sed/awk magic :)
Cheers,
Stan
Given the JSON shown, you could add the following to your pipeline:
jq -c 'map({(.name): (if .type == "int" then 1234567890 else "xxxxxxxxxx" end)})|add'
With that JSON, the output would be:
{"id":1234567890,"test_string":"xxxxxxxxxx"}
However, it would be far better if you combined the three calls to jq into one.
Title may be incorrect as I'm not actually sure where this is failing. I have a bash script running in one directory, and a JSON file I need a value from in a different directory. I want to copy the value from the external directory into an identical JSON file in the current directory.
I'm using jq to grab the value, but I can't figure out how to grab from a directory other than the one the script is running in.
The relevant bits of file structure are as follows;
cloudformation
- parameters_v13.json
environment_files
- prepare_stack_files.json (the script this is run from)
- directory, changes based on where the script is pointed
- created directory where created files are being output
- GREPNAME_parameters.json
The chunk of the JSON file I'm interested in looks like this;
[
{
"ParameterKey": "RTSMEMAIL",
"ParameterValue": "secretemail"
}
]
The script needs to get the "secretemail" from cloudformation/parameters_v13.json and paste it into the matching RTSMEMAIL field in the GREPNAME_parameters.json file.
I've been attempting the following with no luck - nothing is output. No error message either, just blank output. I know the GREPNAME path is correct because it's used elsewhere with no issues.
jq --arg email "$EMAIL" '(.[] | select(.ParameterKey == "RTSMEMAIL") | .ParameterValue) |= $email' ../cloudformation/parameters_v13.json | sponge ${GREPNAME}_parameters.json
This jq filter should help you get secretmail string
jq '.[] | select(.ParameterKey=="RTSMEMAIL") | .ParameterValue' json
"secretemail"
Add a -r file for raw output to remove quotes around the value
jq -r '.[] | select(.ParameterKey=="RTSMEMAIL") | .ParameterValue' json
secretemail
--raw-output / -r:
With this option, if the filter’s result is a string then it will be written directly to standard output rather than being formatted as a JSON string with quotes. This can be useful for making jq filters talk to non-JSON-based systems.
As I could see it you are trying to pass args to jq filter, for extraction you can do something first by setting the variable in bash
email="RTSMEMAIL"
and now pass it to the filter as
jq --arg email "$email" -r '.[] | select(.ParameterKey==$email) | .ParameterValue' json
secretemail
Now to replace the string obtained from parameters_v13.json file to your GREPNAME_parameters.json do the following steps:-
First storing the result from the first file in a variable to re-use later, I have used the file to extract as json, this actually points your parameters_v13.json file in another path.
replacementValue=$(jq --arg email "$email" -r '.[] | select(.ParameterKey==$email) | .ParameterValue' json)
now the $replacementValue will hold the secretmail which you want to update to another file. As you have indicated previously GREPNAME_parameters.json has a similar syntax as of the first file. Something like below,
$ cat GREPNAME_parameters.json
[
{
"ParameterKey": "SOMEJUNK",
"ParameterValue": "somejunkvalue"
}
]
Now I understand your intention is replace "ParameterValue" from the above file to the value obtained from the other file. To achieve that,
jq --arg replace "$replacementValue" '.[] | .ParameterValue = $replace' GREPNAME_parameters.json
{
"ParameterKey": "SOMEJUNK",
"ParameterValue": "secretemail"
}
You can then write this output to the a temp file and move it back as the GREPNAME_parameters.json. Hope this answers your question.
#Alex -
(1) sponge simply provides a convenient way to modify a file without having to manage a temporary file. You could use it like this:
jq ........ input.json | sponge input.json
Here, "input.json" is the file that you want to edit "in place". If you want to avoid overwriting the input file, you would not use sponge. In fact, I would recommend against doing so until you're absolutely sure that's what you want.
(2) There are several strategies for achieving what you have described using jq. They basically fall into two categories: (a) invoke jq twice; (b) invoke jq once.
Ignoring the sponge part:
the pattern for using jq twice would be as follows:
param=$(jq -r '.[]
| select(.ParameterKey == "RTSMEMAIL")|.ParameterValue
' cloudformation/parameters_v13.json )
jq --arg param "$param" -f edit.jq input.json
assuming you have jq 1.5, the pattern for doing everything with just one invocation of jq would be:
jq --argfile p cloudformation/parameters_v13.json -f manage.jq input.json
Here, edit.jq and manage.jq are files containing suitable jq programs.
Based on my understanding of your requirements, edit.jq might look like this:
(.[] | select(.ParameterKey == "RTSMEMAIL")|.ParameterValue) |= $param
And manage.jq might look like this:
($p[] | select(.ParameterKey == "RTSMEMAIL")|.ParameterValue) as $param
| (.[]| select(.ParameterKey == "RTSMEMAIL")|.ParameterValue) |= $param
I'm trying to split a json file into various json files. The input (r1.json) looks like :
{
"results" : [
{
content 1
}
,
{
content 2
}
,
{
content n
}
]
}
I'd like the output to be n files : 1.json, 2.json, n.json. Respectively containing {content 1}, {content 2} and {content n}.
I tried :
for i in {0..24}; do cat r1.json | jq '.results[$i]' >> $i.json; done
But I have the following error: error: i is not defined
While the above answers are correct, note that interpolating shell variables in jq scripts is a terrible idea for all but the most trivial of scripts. On any of the solutions provided, replace the following:
jq ".results[$i]"
With the following:
jq --arg i "$i" '.results[$i | tonumber]'
Try
for i in {0..24}; do cat r1.json | jq ".results[$i]" >> $i.json; done
Note that shell variables can't be expanded inside of single-quotes.
IHTH
The single quotes are probably what is messing you up. Bash variables are not expanded in single quotes. You are passing a literal string .results[$i] to jq. Try double quotes instead:
for i in {0..24}; do
cat r1.json | jq ".results[$i]" >> $i.json
done
When I curl to my URL, I get a JSON in the following format:
{"busyexecutors":0,
"computers":[{"displayName":"Master","actions":[{},{},{}]},
{"displayName":"137.0.01","actions":[{},{},{}]}]}
I want to extract only displayName where it's not equal to Master. So the output should be "137.0.0.1".
Let me know whether I can achieve this without external utilities like jq.
There are few good reasons not to use a proper JSON parser when working with JSON.
jq -r '.computers | .[].displayName | select(.!="Master")' <<EOF
{"busyexecutors":0,
"computers":[{"displayName":"Master","actions":[{},{},{}]},
{"displayName":"137.0.01","actions":[{},{},{}]}]}
EOF
As has been noted, this is a bad idea. However, if you insist to do it:
#!/usr/bin/awk -f
{
split($0, z, /"/)
for (y in z)
if (z[y] == "displayName")
if (z[y+2] != "Master")
print z[y+2]
}