0

For supervision system, I need to return 2 values about latency to my supervisor server thru nrpe.

Here the values that I'm working on (I put this in a file : test.txt) :

{"status":"success","data":{"resultType":"vector","result":[{"metric":{"project_site":"AUB"},"value":[1575277537.052,"0.3889104875437488"]},{"metric":{"project_site":"VDR"},"value":[1575277537.052,"0.2267407994117705"]}]}}

I need to extract 0.3889104875437488 and 0.2267407994117705

I'm using this :

for i in $(""cat test.txt | awk -F ',' '{print $5 $NF}' | grep -o '[0.0001-9999.9]\+'""); do echo $i; done

I'm not sure that's the best method, especially since I have to add this : "AUB" for row 1 and "VDR" for row 2 before each line. Like :

AUB : 0.3889104875437488 seconds
VDR : 0.2267407994117705 seconds
oguz ismail
  • 1
  • 16
  • 47
  • 69
Vorbisset
  • 27
  • 4

2 Answers2

2

Use for parsing JSON, for example:

$ jq -r '.data.result[] | "\(.metric.project_site) : \(.value[1]) seconds"' file
AUB : 0.3889104875437488 seconds
VDR : 0.2267407994117705 seconds
oguz ismail
  • 1
  • 16
  • 47
  • 69
0

I have upvoted the answer by @oguzismail, and will repeat their suggestion to use jq instead if at all feasible.

If your input is not valid JSON, there are several things wrong with your approach, several of them related more to efficiency and common practice than outright erroneous.

  1. Your regex is wrong. See below.
  2. Avoid the useless cat.
  3. If you are using Awk anyway, you don't need grep. See useless use of grep.
  4. Quote your variable.
  5. Only in this case, you want to remove the useless echo entirely. Capturing standard output so that you can echo it to standard output is simply a waste of processes (unless you specifically wanted to break the quoting, as a special case of the previous item; but that is not the case here).
  6. It is unclear what you hope for the empty string "" to accomplish. After the shell is done with quote removal, ""cat is simply cat.

In some more detail, [0.0001-9999.9] matches a single character which is 0 or . or 0 (oh we mentioned that already, didn't we?) or 0 (ditto) or between 1 and 9 or 9 (etc etc). In short, grep is not at all the right tool for searching for number ranges; fortunately, Awk can do that easily too.

Here, then, is an attempt to refactor to remove these problems.

awk -F ',' '{ split("5:" NF, a, ":"); split("AUB:VDR", l, ":")
  for (i=1; i<=2; i++) {
    n = $a[i]; gsub(/[]}"]+/, "", n);
    if (n >= 0.0001 && n <= 9999.9)
      print l[i] ": " n " seconds"} }' test.txt

This is extremely brittle because it hard-codes the locations of the strings within the surface structure of the (not?) JSON data, which could change without warning.

The split is a hack to get the numbers 5 and NF into an array a. We create a second array with the same length for the corresponding labels. We then loop over the first array and use the numbers as indices into the current record's fields. We trim off any quoting and brackets, and then perform the numeric comparison on the thus extracted field. At the end, we add the corresponding label from the other array in front of the printed text.

tripleee
  • 175,061
  • 34
  • 275
  • 318