1

I am trying to update a couple values in a json array (separate file) with a shell script. Basically the logic is, set an environment variable called URL, ping that URL and add it to the json-- if 0, update another json field to SUCCESS, else update to FAILED.

Here is are the files:

info.json:

{
 "name": "PingTest",",
 "metrics": [
{
  "event_type": "PingResult",
  "provider": "test",
  "providerUrl": "URL",
  "providerResult": "RESULT"
}
]
}

pinger.sh:

#!/bin/sh

JSON=`cat info.json` #read in JSON

#Assume URL variable is set to www.dksmfdkf.com 
ping -q -c 1 "$URL" > /dev/null #ping url
if [ $? -eq 0 ]; then #if ping success, replace result in json template
  JSON=`echo ${JSON} | jq --arg v "$URL" '.metrics[].providerUrl |= $v' 
  info.json`
  JSON=`echo ${JSON} | jq '.metrics[].providerResult |= "SUCCESS"' info.json`
else
  JSON=`echo ${JSON} | jq --arg v "$URL" '.metrics[].providerUrl |= $v' 
  info.json`
  JSON=`echo ${JSON} | jq '.metrics[].providerResult |= "FAILED"' info.json`
fi

#Remove whitespace from json
JSON=`echo $JSON | tr -d ' \t\n\r\f'`

#Print the result
echo "$JSON"

The problem is my json file isn't getting updated properly, example result when running:

home:InfraPingExtension home$ ./pinger.sh
ping: cannot resolve : Unknown host
{
  "name": "PingTest",
  "metrics": [
  {
    "event_type": "PingResult",
    "provider": "test",
    "providerUrl": "",
    "providerResult": "RESULT"
  }
 ]
 }
{
  "name": "PingTest",
  "metrics": [
{
  "event_type": "PingResult",
  "provider": "test",
  "providerUrl": "URL",
  "providerResult": "FAILED"
}
  ]
}

{"name":"PingTest","metrics":[{"event_type":"PingResult","provider":"test","providerUrl":"URL","providerResult":"RESULT"}]}
nobrac
  • 372
  • 1
  • 6
  • 16
  • 1
    FYI -- all-caps variable names are used for variables with meaning to the shell or OS; all other names are reserved for application usage (so your own variables should have at least one lowercase letter so they can't conflict with names reserved by future versions of the shell). See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html, fourth paragraph. – Charles Duffy Jan 29 '18 at 16:09
  • 1
    And btw, if you don't want semantically-irrelevant whitespace in your JSON, use the `-c` argument to `jq`; that way you don't corrupt your data (if there are actually spaces within it). – Charles Duffy Jan 29 '18 at 16:09
  • 1
    Most importantly, right now, your `$?` doesn't refer to the success of `ping` but refers instead to the success of the `jq` you're running *after* the `ping`. This is part of why instead of running `ping` and then testing `$?`, it's better practice to directly write `if ping -c 1 "$host"; then` -- there's no way your result can be something other than what you meant to test. – Charles Duffy Jan 29 '18 at 16:11
  • Possible duplicate of [Jq to replace text directly on file (like sed -i)](https://stackoverflow.com/questions/36565295/jq-to-replace-text-directly-on-file-like-sed-i) – Samuel Kirschner Jan 29 '18 at 16:32
  • BTW, I'd strongly suggest having a single JSON template that *doesn't* change you use as your input file, rather than re-processing the same file over-and-over; output is more predictable if input is fixed, as otherwise you can get into a state where one transient failure corrupts the file causing all future runs to fail. – Charles Duffy Jan 29 '18 at 17:16

1 Answers1

3

This would be greatly simplified by only calling jq once.

host=${URL#http://}; host=${host#https://}; host=${host%%/*}
if ping -q -c 1 "$host"; then
  result=SUCCESS
else
  result=FAILED
fi

JSON=$(
  jq -c \
     --arg url "$URL" \
     --arg result "$result" \
     '.metrics[].providerUrl |= $url
      | .metrics[].providerResult |= $result
  ' info.json
)
Community
  • 1
  • 1
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441