parsing json with shell script - json

Wanted to parse json:
{"FileStatus":"accessTime":1472892839430,"blockSize":134217728,"childrenNum":0,"fileId":17226,"group":"admin","length":115714,"modificationTime":1469649837471,"owner":"admin","pathSuffix":"","permission":"755","replication":2,"storagePolicy":0,"type":"FILE"}}
I tried something like this but not able to get it.
$ {"FileStatus":{"accessTime":1472892839430}} | jq '.FileStatus.accessTime'
Error:
-bash: {FileStatus:{accessTime:1472892839430}}: command not found`
Can someone help me to parse this whole json.

To make a command read a string on stdin in bash, use a "here string" like this:
$ jq '.FileStatus.accessTime' <<<'{"FileStatus":{"accessTime":1472892839430}}'
1472892839430
Also, you need to properly quote the text, so that bash doesn't try to interpret in some way you don't intend. When you want to preserve it literally, use single quotes (').

Related

When creating a variable from command output, Bash removes a backslash from the JSON. How do I make it keep both backslashes to maintain valid JSON?

I'm doing the following to capture some ADO JSON data:
iteration="$(az boards iteration team list --team Test --project Test --timeframe current)"
Normally, the output of that command contains a JSON key/value pair like the following:
"path": "Test\\Sprint1"
But after capturing the STDOUT into that iteration variable, if I do
echo "$iteration"
That key/value pair becomes
"path": "Test\Sprint1"
And if I attempt to use jq on that output, it breaks because it's not recognized as valid JSON any longer. I'm very unfamiliar with Bash. How can I get that JSON to remain valid all the way through?
As already commented by markp-fuso:
It looks like your echo command is interpreting the backslashes. You can confirm this by running echo 'a\\b' and looking at the output.
The portable way to deal with such problems is to use printf instead of echo:
printf %s\\n "$iteration"

Tell Json this all one line

I am writing a JSON template for AWS SSM document.
Once of the commands I am trying to run looks like this:
"ssh-keygen -q -t rsa -N '' <<< ""$'\n'"y" 2>&1 >/dev/null",
However, due to the "" after the <<< JSON thinks that this is a new line and is expecting a comma.
Is there a way I can tell JSON that that is a single command and need to be treated as a single line?
You need to escape the double quotes. So " inside your json string becomes \".

Compress heredoc declaration to one line in bash?

I have this which works to declare a JSON string in a bash script:
local my_var="foobar"
local json=`cat <<EOF
{"quicklock":"${my_var}"}
EOF`
The above heredoc works, but I can't seem to format it any other way, it literally has to look exactly like that lol.
Is there any way to get the command to be on one line, something like this:
local json=`cat <<EOF{"quicklock":"${my_var}"}EOF`
that would be so much nicer, but doesn't seem to take, obviously simply because that's not how EOF works I guess lol.
I am looking for a shorthand way to declare JSON in a file that:
Does not require a ton of escape chars.
That allows for dynamic interpolation of variables.
Note: The actual JSON I want to use has multiple dynamic variables with many key/value pairs. Please extrapolate.
I'm not a JSON guy, don't really understand the "well-formed" arguments in the discussion above, but, you can use a 'here-string' rather than a 'here-document', like this:
my_var="foobar"
json=`cat <<<{\"quicklock\":\"${my_var}\"}`
why not use jq? It's pretty good at managing string interpolation and it lints your structure.
$ echo '{}' >> foo.json
$ declare myvar="assigned-var"
$ jq --arg ql "$myvar" '.quicklock=$ql' foo.json
the text that comes out on the other end of that call to jq can then be cat into a file or whatever you wanna do. text would look something like this:
{"quicklock": "assigned-var"}
You can do this with printf:
local json="$(printf '{"quicklock":"%s"}' "$my_var")"
(Never mind that SO's syntax highlighting looks odd here. Posix shell command substitution allows nesting one level of quotes.)
A note (thanks to Charles Duffy's comment on the question): I'm assuming $my_var is not controlled by user input. If it is, you'll need to be careful to ensure it is legal for a JSON string. I highly recommend barring non-ASCII characters, double quotes, and backslashes. If you have jq available, you can use it as Charles noted in the comments to ensure you have well-formed output.
You can define your own helper function to address the situation with missing bash syntax:
function begin() { eval echo $(sed "${BASH_LINENO[0]}"'!d;s/.*begin \(.*\) end.*/\1/;s/"/\\\"/g' "${BASH_SOURCE[0]}"); }
Then you can use it as follows.
my_var="foobar"
json=$(begin { "quicklock" : "${my_var}" } end)
echo "$json"
This fragment displays the desired output:
{ "quicklock" : "foobar" }
This is just a proof of concept. You can define your syntax in any way you want (such as end of the input by the custom EOF string, correctly escape invalid characters). For example, since Bash allows function identifiers using characters other than alphanumeric characters, it is possible to define such a syntax:
json=$(/ { "quicklock" : "${my_var}" } /)
Moreover, if you relax the first criterion (escape characters), ordinary assignment will nicely solve this problem:
json="{ \"quicklock\" : \"${my_var}\" }"
How about just using the shell's natural concatenation of strings? If you concatenate ${mybar} rather than interpolate it, you can avoid escapes and get everything on one line:
my_var1="foobar"
my_var2="quux"
json='{"quicklock":"'${my_var1}'","slowlock":"'$my_var2'"}'
That said, this is a pretty crude scheme, and as others have pointed out you'll have problems if the variables, say, contain quote characters.
Since no escape chars is strong requirement here is a here-doc based solution:
#!/bin/bash
my_var='foobar'
read -r -d '' json << EOF
{
"quicklock": "$my_var"
}
EOF
echo "$json"
It will give you the same output as the first solution I mentioned.
Just be careful, if you would put first EOF inside double quotes:
read -r -d '' json << "EOF"
$my_var would not be considered as a variable but as a plain text, so you would get this output:
{
"quicklock": "$my_var"
}

Bash tuple on json string

I have a specific problem. I make email variable in bash script like:
tDestinationEmail=email#email.com
and if I enter an email after the sign = my json should look like this:
{"ToAddresses": ["email#email.com"]}
I try to do it with
tDestinationEmailJSON='{"ToAddresses": ["$tDestinationEmail"]}'
but on the output i getting
{"ToAddresses": ["$tDestinationEmail"]}
Maybe whom know solution how i can do it ? Please suggest!
jq is the right tool for JSON data manipulation:
tDestinationEmail="email#email.com"
jq -nc --arg email "$tDestinationEmail" '{ToAddresses: [$email]}'
The output:
{"ToAddresses":["email#email.com"]}
From man page of bash:
"Enclosing characters in single quotes preserves the literal value of each character within the quotes."
So when you call $tDestinationEmail will be treated as string and will not call the value of the variable.
Using double quotes:
tDestinationEmailJSON='{"ToAddresses": ['"\"$tDestinationEmail\""']}'

‘.”line”’ not accepted as valid syntax by jq - "unexpected INVALID_CHARACTER"

I'm trying to make a GET request with curl in a bash file.
So I call curl, and get a JSON response from my server, and I try to get the object line which is part of the response, and I do so with jq, so I can print the value.
But its not working.
My response is something like this:
{"line":"Azul", "id":"j3453j45n35", "lat":"39.091937", "long":"-9.265441"}
My bash script:
#!/bin/bash
while :
do
cmd=$(curl -i -H "Content-Type: application/json" http://localhost:8080/cards/exists/1 | jq ‘.”line”’)
sleep 2
done
The result:
jq: error: syntax error, unexpected INVALID_CHARACTER, expecting $end (Unix shell quoting issues?) at , line 1:
‘.”line”’
jq: 1 compile error
(23) Failed writing body
Whats going wrong?
I followed plenty of responses people advised online, but I keep getting the same response.
My json object seems to be correct.
I'm running this file on MacOS Sierra
There are two problems with your code:
You're using non-ASCII quotes (‘ ” ” ’), which jq doesn't understand:
Replace them with their ASCII equivalents: ' " " '
On macOS, avoid a text editor such as the standard TextEdit.app that has the "smart quotes" feature turned on, or turn that feature off via the menu system: Edit > Substitutions > Smart Quotes
It is this feature that replaces ASCII quoting chars. with their non-ASCII, typographical equivalents, as you type.
Generally, consider using a dedicated source-code editor for editing your code, such as Visual Studio Code (free) or Atom (free) or Sublime Text (paid).
Your curl command includes header output (-i), which jq chokes on - simply omit the -i:
#!/bin/bash
while :; do
cmd=$(curl -H 'Content-Type: application/json' 'http://localhost:8080/cards/exists/1' |
jq '.line')
sleep 2
done
While '."line"' would have worked too, there's no need for the extra layer of quoting for simple property names like that.
Also, it's better to enclose strings that you want to be interpreted literally in '...' in the shell.