This is my data file: explorejq.json
-
{
"apiVersion": "v1",
"data": {
"app.properties": "some.base64encoded.data"
},
"kind": "ConfigMap",
"metadata": {
"creationTimestamp": "2021-05-17T09:54:15Z",
"name": "myappproperties",
"namespace": "myappnamespace",
"resourceVersion": "352258550",
"selfLink": "/api/v1/namespaces/myappnamespace/configmap/myappproperties",
"uid": "cb23197e-54ee-412a-a07a-7d02df3d59a1"
},
"type": "IncorrectType"
}
And i want to retrive the value of key app.properties
which is nested in data
. I know the right way of doing this is using -
cat explorejq.json | jq '.data ' | jq '.["app.properties"]'
or
cat explorejq.json | jq '.data | .["app.properties"]'
and i get
output: "some.base64encoded.data"
as required
Now the problem is one of my fellow developer is using jq commands without single quotes for the last part. Example -
cat explorejq.json | jq '.data ' | jq .["app.properties"]
or
cat explorejq.json | jq '.data ' | jq .[".app.properties"]
or
cat explorejq.json | jq '.data ' | jq .["., ., app.properties"]
and getting
output -
{
"app.properties": "some.base64encoded.data"
}
"some.base64encoded.data"
Now, i know all the above three are incorrect ways, but i need to understand whats happening in these cases so i can explain the same.
Can someone explain what happens when jq commands are used without single quote and particularly whats happening in above cases.
Edit -
Basically the issue here is with jq .["app.properties"]
. Shell is interpreting it before passing it to jq.
echo jq .["., ., app.properties"]
output: jq ..
.
Same is the case with rest of the two patterns i mentioned.
So posted a new Q here - what is .. (two dots) in jq filter
CodePudding user response:
Actually, also cat explorejq.json | jq '.data ' | jq '."app.properties"'
would work (or simplified to jq '.data."app.properties"' explorejq.json
). The relevant part is that "app.properties"
is surrounded by quotes as it needs to be a JSON string (within jq). In turn, the whole jq filter is also a string for the calling environment (within the shell). That's why you also need to quote the filter (if it contains spaces, quotes etc). However, as it contains double quotes for the JSON string, single quotes are the appropriate choice for the jq filter string. If you did't use those outer quotes, the shell would interpret itself the inner ones as string boundaries and as such they wouldn't appear in the actual jq filter anymore. As a consequence, jq would fail in rendering app.properties
as actual JSON string.
CodePudding user response:
The string quotes are part of bash scripting and are needed if you want to pass an argument that contains spaces to a command. In your case the arguments does not contain spaces, so no quotes are needed to pass .["app.properties"]
as argument to jq
.
In the last case bash concatenates one string with two spaces .["., ., app.properties"]
that is passed to jq
as one argument.
So your fellow developer is doing everything right ;-) Although I myself also find it clearer to use simple quotes for the entire jq program.
CodePudding user response:
You've already figured out that the shell is processing .["., ., app.properties"]
into ..
but you may not have figured out why yet.
Unquoted square brackets are pattern-matching syntax for a single character, similar to the way ?
is a wildcard for any single character and *
is a wildcard for zero or more characters. In this case, you've created a pattern-match for any file with a name starting with .
and followed by any single character from the set ., ., app.properties
which simplifies to the set ., aeioprst
. Since ..
is present in every directory, it always matches and you get ..
. However, if for example you had a file called .p
in the current directory, it would match too and you'd send an extra argument to jq
. The immediate lesson of the story is always single-quote your filter argument to jq
. The broader moral is that it's hard to learn and remember all the shell rules and behaviours, but it's much easier to remember a safe subset. If you know that single quotes pass the entire argument through verbatim, and if you stick to them for any argument containing characters you're unsure might have special behaviour, you don't need to worry about all the things you don't know.
CodePudding user response:
You may want to take advantage of the -f
option of jq, where you can put your filter program in a file, and have jq read it from the file. This saves you from the hassles of shell quoting.