How to extract data from a JSON file into a variable - bash

I have the following json format, basically it is a huge file with several of such entries.
[
{
"id": "kslhe6em",
"version": "R7.8.0.00_BNK",
"hostname": "abacus-ap-hf-test-001:8080",
"status": "RUNNING",
},
{
"id": "2bkaiupm",
"version": "R7.8.0.00_BNK",
"hostname": "abacus-ap-hotfix-001:8080",
"status": "RUNNING",
},
{
"id": "rz5savbi",
"version": "R7.8.0.00_BNK",
"hostname": "abacus-ap-hf-test-005:8080",
"status": "RUNNING",
},
]
I wanted to fetch all the hostname values that starts with "abacus-ap-hf-test" and without ":8080" into a variable and then wanted to use those values for further commands over a for loop something like below. But, am bit confused how can I extract such informaion.
HOSTAME="abacus-ap-hf-test-001 abacus-ap-hf-test-005"
for HOSTANAME in $HOSTNAME
do
sh ./trigger.sh
done

The first line command update to this:
HOSTAME=$(grep -oP 'hostname": "\K(abacus-ap-hf-test[\w\d-]+)' json.file)
or if you sure that the hostname end with :8080", try this:
HOSTAME=$(grep -oP '(?<="hostname": ")abacus-ap-hf-test[\w\d-]+(?=:8080")' json.file)
you will find that abacus-ap-hf-test[\w\d-]+ is the regex, and other strings are the head or the end of the regex content which for finding result accuracy.

Assuming you have valid JSON, you can get the hostname values using jq:
while read -r hname ; do printf "%s\n" "$hname" ; done < <(jq -r .[].hostname j.json)
Output:
abacus-ap-hf-test-001:8080
abacus-ap-hotfix-001:8080
abacus-ap-hf-test-005:8080

Related

jq does not show null output

I have the following code in the command line script:
output_json=$(jq -n \
--argjson ID "${id}" \
--arg Title "${title}" \
--argjson like "\"${like}\"" \
'$ARGS.named')
I put the id, title and like variables into the jq. I get the following output:
[
{
"ID": 6,
"Title": "ABC",
"like": ""
},
{
"ID": 22,
"Title": "ABC",
"like": "Yes"
}
]
But, I am trying to get the output in the following format, i.e. with null:
[
{
"ID": 6,
"Title": "ABC",
"like": null
},
{
"ID": 22,
"Title": "ABC",
"like": "Yes"
}
]
I don't quite get it is it possible to do this in general, or is it a problem with my jq command?
And as far as I understood "like": "" is not the same as "like": null. I am also a little confused now, and do not really understand what is the correct choice to use.
By using --argjson you need to provide valid JSON-encoded argument, thus if you want to receive null the value needs to be literally null. Your solution, however, adds quotes around it, so it can never be evaluated to null. (Also, it will only be a valid JSON string if it follows the JSON encoding for special characters such as the quote characters itself).
If you want to have a JSON string in the regular case, and null in the case where it is empty, import the content of ${like} as string using --arg and without the extra quotes (just as you do with ${title}), then use some jq logic to turn the empty string into null. An if statement would do, for example:
like=
jq -n --arg like "${like}" '{like: (if $like == "" then null else $like end)}'
{
"like": null
}

Appending to a configuration file

I am creating a script which updates hosts in an application, the config file for each host looks like that below. The script generates the hosts correctly but I need to append every } with a comma , except the last host.
I have tried numerous things but the closest I have got is putting the hosts content on a single line and running a IFS statement against it. Im also not sure how best to approach this, can anyone advise?
{
"cmd": "ssh user#webserver",
"inTerminal": "new",
"name": "webserver",
"theme": "basic",
"title": "Webserver",
}
example of what I am trying to achieve
{
"cmd": "ssh user#webserver",
"inTerminal": "new",
"name": "webserver",
"theme": "basic",
"title": "Webserver",
},
{
"cmd": "ssh user#db",
"inTerminal": "new",
"name": "db server",
"theme": "basic",
"title": "db",
},
{
"cmd": "ssh user#mail",
"inTerminal": "new",
"name": "mail server",
"theme": "basic",
"title": "mail server",
}
You can do things like:
#!/bin/sh
for f in $(generate-host-list); do
read -d \000 c < "$f"
list="$list${list+,
}$c"
done
echo "$list"
If you are just writing to a file that can be simpler (no need for the read, just cat the file). Similarly, if you don't care about munging whitespace, you could do list="$list${list+,}$(cat "$f"). If you are using bash or some other shells you can do non-portable things like += to clean it up.
You can do it like this:
sed '$q; s/^}$/},/' <in_file >out_file
The above sed command works as follows: First check if you've reached the last
line, and if so quit. Otherwise, it'll check if the only character on the line
is }, and if so replace it with },.

Invalid numeric literal when passing a truncated JSON object to jq

I have a response from cURL which looks like this:
{"username": "bot", "verified": true, "locale": "en-US", "mfa_enabled": false, "bot": true, "id": "123", "flags": 0, "avatar": null, "discriminator": "3114", "email": null} 200
which is stored in variable called auth
Then I want to be able to loop that object doing this:
response=$(jq -c "." <<< "${auth::-3}")
Note that I remove the last 3 characters because those are the status code.
So technically it should work, but it returns: parse error: Invalid numeric literal at line 1, column 11
If I enter the raw JSON as a string, it works. But not like this. Why?
Consider:
response=$(jq -n --argjson auth "${auth% *}" '$auth')
...which will work correctly with versions of bash too old to correctly support ${auth::-3} (a 4.x-only feature), and which will also log enough details to track down any issue caused by the content passed to jq when run with bash -x yourscript.

JQ query on JSON file

I am having below code in JSON file.
{
"comment": {
"vm-updates": [],
"site-ops-updates": [
{
"comment": {
"message": "You can start maintenance on this resource"
},
"hw-name": "Machine has got missing disks. "
}
]
},
"object_name": "4QXH862",
"has_problems": "yes",
"tags": ""
}
I want to separate "hw-name" from this JSON file using jq. I've tried below combinations, but nothing worked.
cat jsonfile | jq -r '.comment[].hw-name'
cat json_file.json | jq -r '.comment[].site-ops-updates[].hw-name'
Appreciated help from StackOverflow!!!
It should be:
▶ cat jsonfile | jq -r '.comment."site-ops-updates"[]."hw-name"'
Machine has got missing disks.
Or better still:
▶ jq -r '.comment."site-ops-updates"[]."hw-name"' jsonfile
Machine has got missing disks.
From the docs:
If the key contains special characters, you need to surround it with double quotes like this: ."foo$", or else .["foo$"].

json processing in .sh files

[
{
"id": "1636ea48-28b7-783a-48dd-5e041f10d9e6",
"name": "Test_Component1",
"desiredVersions": [],
"children": false
},
{
"id": "1636f939-136f-4609-ab93-238b1af193fe",
"name": "Test_Component2",
"desiredVersions": [],
"children": false
}
]
I am writing command in Execute Shell window in Jenkins. I have this json in a variable. I want to extract both Id values so further processing in next set of command can be done.
Using jq:
$ echo "$var" | jq '.[].id'
"1636ea48-28b7-783a-48dd-5e041f10d9e6"
"1636f939-136f-4609-ab93-238b1af193fe"
is it a string? If so, you can use a regexp expression to extract the ID´s values. Like:
(\"id\"\:\W)\"(.+)(\"\,)

Resources