test.sh is not replacing test.json parameter value and gives jq compilation error.
test.json
{
"ParameterKey": "Project",
"ParameterValue": "<check>"
}
test.sh
cat test.json | jq \
'map(if .ParameterKey == "Project"
then . + {"ParameterValue" : "val" }
else . end)' > result.json
The reason you're seeing that message is that the map() expression is enumerating the values of your object ("Project" and "<check>") invoking the if .ParameterKey ... expression on each of them. Unfortunately those are strings and the .ParameterKey part of your if condition won't work with string values so jq gives you the error Cannot index string with string “ParameterKey”.
You probably only want the map() if your test.json contains an array of objects. If your test.json contains an object at the top level such as {"ParameterKey": "Project", "ParameterValue": "<check>"} then you should remove the map(). e.g.
$ cat test.json | \
jq 'if .ParameterKey == "Project" then . + {"ParameterValue" : "val" } else . end'
{
"ParameterKey": "Project",
"ParameterValue": "val"
}
Related
I am trying to query json using jq in bash scripting
file customers.json contains the following
[
{
"_id": "5968dd23fc13ae04d9000001",
"product_name": "sildenafil citrate",
"supplier": "Wisozk Inc",
"quantity": 262,
"unit_cost": "$1047"
},
{
"_id": "5968dd23fc13ae04d9000002",
"product_name": "Mountain Juniperus ashei",
"supplier": "Keebler-Hilpert",
"quantity": 292,
"unit_cost": "$874"
},
{
"_id": "5968dd23fc13ae04d9000003",
"product_name": "Dextromathorphan HBr",
"supplier": "Schmitt-Weissnat",
"quantity": 211,
"unit_cost": "$2053"
}
]
when i run following bash script
key="supplier"
value="Wisozk Inc"
jq ".[] | select(.$key==$value)" customers.json
It throws the following error
jq: error: syntax error, unexpected IDENT, expecting ';' or ')' (Unix shell quoting issues?) at <top-level>, line 1:
.[] | select(.supplier == Wisozk Inc)
jq: 1 compile error
I think the space between "Wisozk" and "Inc" is the problem, what to do?
Do not let your shell variables to be interpolated in jq under double quotes. The error is because of spaces in the value field, the variable $value undergoes word-splitting by and the filter expression of jq gets two words Wisozk and Inc instead of "Wisozk Inc".
Just pass your variables to jq's context using the --arg field and let it deal with it.
jq --arg k supplier --arg v "Wisozk Inc" 'map(select(.[$k] == $v))' json
This question is in parts duplicate to both the below questions, but not as a whole.
passing arguments to jq filter
Passing bash variable to jq
I need help in correcting jq test cases syntax. Following is output file & trying to test ID list with command below. Gives error index to string type.
[[ $(echo $output| jq -r '.output.value[] | select(.identity).id_list') == *"id2"* ]]
output = {
"resource_output": {
"value": {
"identity": [
{
"id_list": [
"/subscriptions/---/id1",
"/subscriptions/---/id2",
"/subscriptions/--/id3"
],
"principal_id": "",
"tenant_id": "",
"type": "managed"
}
]
}
}
Your query does not match the sample JSON, and you have not indicated what output you are expecting, but the following variation of your query illustrates how to use select and test with your data along the lines suggested by your attempt:
echo "$output" |
jq -r '.resource_output.identity[].id_list[] | select(test("id2"))'
Output:
/subscriptions/---/id2
I have the the following input json:
{
"TagList": [
{
"Key": "Environment",
"Value": "foo"
},
{
"Key": "ENVIRONMENT",
"Value": "bar"
}
]
}
I want to get the values of tags with the key ENVIRONMENT using jq:
jq -r '.TagList[] | select(.Key=="ENVIRONMENT") | .Value' input.json
But as it turned out, the key could be also Environment. I try get both using this command:
jq -r '.TagList[] | select((.Key=="ENVIRONMENT") | .Value' or .Key=="Environment" | .Value)
but get the following error:
jq: error: syntax error, unexpected $end, expecting ';' or ')' (Unix shell quoting issues?) at <top-level>, line 1:
.TagList[] | select((.Key=="ENVIRONMENT") | .Value
jq: 1 compile error
How to get both of those tags?
You can use the following command:
jq '.TagList[]|select(.Key=="Environment" or .Key=="ENVIRONMENT").Value'
Generalizing a bit:
.TagList[]
| select(.Key | ascii_upcase == "ENVIRONMENT").Value
I am using jq to parse log data, occasionally the logs contain malformed stuff (invalid json), when this happens, jq aborts processing at that point.
Is there a way to have jq keep processing what it can, while reporting the problems via stderr?
I understand that if you have newlines in your JSON, jq may have trouble if it starts with the next line, but in such cases you will still eventually get to the point that you find the start of a legitimate json message and can continue processing.
With jq-1.5 I was able to do the following:
With this example file:
cat << EOF > example.log
{"a": 1}
{invalid
{"b": 2}
EOF
Output non-json lines as unquoted strings:
cat example.log | jq --raw-input --raw-output '. as $raw | try fromjson catch $raw'
{
"a": 1
}
{invalid
{
"b": 2
}
Silently skip non-json lines:
cat example.log | jq --raw-input 'fromjson?'
{
"a": 1
}
{
"b": 2
}
You can add --slurp if the entire input is expected to be a single multiline json blob.
Example files:
cat << EOF > valid-multiline.log
{
"a": 1,
"b": 2
}
EOF
cat << EOF > invalid-multiline.log
{
asdf
"b": 2
}
EOF
Outputs
cat valid-multiline.log | jq --slurp --raw-input --raw-output '. as $raw | try fromjson catch $raw'
{
"a": 1,
"b": 2
}
cat invalid-multiline.log | jq --slurp --raw-input --raw-output '. as $raw | try fromjson catch $raw'
{
asdf
"b": 2
}
If you have jq 1.5, the answer is: yes, though in general, preprocessing (e.g. using hjson or any-json) would be preferable.
Anyway, the idea is simply to take advantage of the try/catch feature. Here is an illustration using the inputs filter. Note that jq should in general be invoked with the -n option for this to work.
recover.jq
def handle: inputs | [., "length is \(length)"] ;
def process: try handle catch ("Failed", process) ;
process
bad.json
[1,2,3]
{id=546456, userId=345345}
[4,5,6]
See jq run:
$ jq -n -f recover.jq bad.json
[
"[1,2,3]",
"length is 3"
]
"Failed"
[
"[4,5,6]",
"length is 3"
]
Suppose I have the following json in a file json.txt
{
"first_name": "John",
"last_name": "Smith",
"things_carried": [
"apples",
"hat",
"harmonica"
],
"children": [
{
"first_name": "Bobby Sue",
"last_name": "Smith"
},
{
"first_name": "John Jr",
"last_name": "Smith"
}
]
}
In shell script I had written the logic to find the size of children array using jq tool .
size=cat json.txt | jq '.children | length'
i=0
while [ $i -le $size ]
do
array[$i]=$(cat json.txt | jq '.children[$i]')
i=`expr $i + 1`
done
On running this it gives the following error -
.children[$i] 1 compile error
It seems that it is not able to replace the variable i in the children[] array , as because if we give the expression -
array[$i]=$(cat json.txt | jq '.children[0]')
it runs well .
Can someone help me .
You're using single quotes around the jq program. Shells do not interpolate variables inside single quotes; this is intentional and the jq manual recommends using single quotes around programs for this reason.
An argument syntax is provided by jq for this purpose. This syntax allows you to set jq variables to the value of shell variables. You could replace your current jq invocation with this:
array[$i]=$(cat json.txt | jq --arg i $i '.children[$i | tonumber]')
It looks like you're just trying to set the children to a bash array variable.
You don't need to loop, just set the array directly.
$ IFS=$'\n'; array=($(jq -c '.children[]' json.txt))
You should use the following syntax:
array[$i]=$(cat json.txt | jq '.children['${i}']')