Issue
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
Solution
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.
- Your regex is wrong. See below.
- Avoid the useless
cat
. - If you are using Awk anyway, you don't need
grep
. See useless use ofgrep
. - Quote your variable.
- Only in this case, you want to remove the useless
echo
entirely. Capturing standard output so that you canecho
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). - It is unclear what you hope for the empty string
""
to accomplish. After the shell is done with quote removal,""cat
is simplycat
.
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.
Answered By - tripleee Answer Checked By - Candace Johnson (WPSolving Volunteer)