1

I have a curl command which returns me this kind of json formated text

[{"id": "nUsrLast//device control", "name": "nUsrLast", "access": "readonly", "value": "0", "visibility": "visible", "type": "integer"}]

I would like to get the value of the field value.

Can someone give me a simple awk or grep command to do so ?

Avinash Raj
  • 172,303
  • 28
  • 230
  • 274
Syf Illis
  • 145
  • 1
  • 12
  • The value of the field value??? – ooga Jul 09 '14 at 14:34
  • Perl is easier: `echo | perl -e ' =~ /\"value\"\s*:\s*\"(([^"]|\\")*)\"/; print $1;'` <-- Tested that, it works. The value in quotes can contain any character other than `"`, but it can also contain backslash-escaped `"` (i.e. `\"`). – Parthian Shot Jul 09 '14 at 14:36
  • @ParthianShot Looks like the awk below is easiest. – ooga Jul 09 '14 at 14:37
  • @ooga True. But it's also wrong, as I pointed out in the comments below it. – Parthian Shot Jul 09 '14 at 14:51
  • You might also want to check out the answers to [this question](http://stackoverflow.com/questions/3858671/unix-command-line-json-parser). – Parthian Shot Jul 09 '14 at 14:58

3 Answers3

2

You could use grep with oP parameters,

$ echo '[{"id": "nUsrLast//device control", "name": "nUsrLast", "access": "readonly", "value": "0", "visibility": "visible", "type": "integer"}]' | grep -oP '(?<=\"value\": \")[^"]*'
0

From grep --help,

  • -P, --perl-regexp PATTERN is a Perl regular expression
  • -o, --only-matching show only the part of a line matching PATTERN

Pattern Explanation:

  • (?<=\"value\": \") Lookbehind is used to set or place the matching marker. In our case, regex engine places the matching marker just after to the string "value": ".
  • [^"]* Now it matches any character except " zero or more times. When a " is detected then the regex engine would stop it's matching operation.
Avinash Raj
  • 172,303
  • 28
  • 230
  • 274
  • 1
    You need to explain the regex, too. :-) – ooga Jul 09 '14 at 14:36
  • I partially fixed it, but there's a fundamental flaw with this regex, which is that, if the JSON is malformed / the curl request fails partway through, and you get something like `{"value": "this is half a st`, it will silently match `this is half a st`. It doesn't check that the value is terminated with a `"` symbol, which is an error condition. – Parthian Shot Jul 09 '14 at 14:54
  • @ParthianShot for your malformed file `grep -oP '(?<=\"value\": \")[^",]*'` – Avinash Raj Jul 09 '14 at 14:58
  • @AvinashRaj Then you always get the trailing `"` and must remove it. – Parthian Shot Jul 09 '14 at 15:00
  • How i get the trailing `"` in my output? Could you post an example. – Avinash Raj Jul 09 '14 at 15:02
2

Here is an awk

awk -v RS="," -F\" '/value/ {print $4}' file
0

How does it work?
Setting RS to , it breaks line to some like this:

awk -v RS="," '{$1=$1}1' file
[{"id": "nUsrLast//device control"
"name": "nUsrLast"
"access": "readonly"
"value": "0"
"visibility": "visible"
"type": "integer"}]

Then /value/ {print $4} prints field 4 separated by "

Jotne
  • 40,548
  • 12
  • 51
  • 55
  • Does this handle backslash-escaped double quotes in the string? And commas in the strings? – Parthian Shot Jul 09 '14 at 14:43
  • @ParthianShot Obviously not, but the data does not seem to require it. – ooga Jul 09 '14 at 14:44
  • Well, assumedly he doesn't want a solution that only works on the specific string given. He's making a curl request and getting arbitrary JSON data. If one of the fields is `"name":"Bob, the builder",` everything breaks. And he didn't specify the value of `value` could only be numeric. – Parthian Shot Jul 09 '14 at 14:47
  • @ParthianShot It will not brake, since it only cares about the section with `value` in it. Does not matter how many `,` there are. But if you have `va,lue`, you get problem, but when do you see some like that? – Jotne Jul 09 '14 at 14:53
  • @Jotne So you're saying this will work if you have something like `"value": "John \"the one, the only\" Smith"`? – Parthian Shot Jul 09 '14 at 14:57
  • @ParthianShot No, but I do assume that value always comes after an handle. If the handle has `,` in, you need to take in care that it does. A normal handle is `value=0`, `value:0` etc – Jotne Jul 09 '14 at 15:01
  • @Jotne That's fair. I only wanted to bring it up so that someone reading the answer is aware of its limitations. If they're only dealing with a numeric field, your solution is perfect. – Parthian Shot Jul 09 '14 at 15:10
0

This solution isn't grep or awk but chances are pretty good your system has perl on it, and this is the best solution thus far:

echo <your_json> | perl -e '<STDIN> =~ /\"value\"\s*:\s*\"(([^"]|\\")*)\"/; print $1;'

It handles the possibility of a failed request by ensuring there is a trailing " character. It also handles backslash-escaped " symbols in the string and whitespace between "value" and the colon character.

It does not handle JSON broken across multiple lines, but then none of the other solutions do, either.

\"value\"\s*:\s*\" Ensures that we're dealing with the correct field, then

(([^"]|\\")*) Captures the associated valid JSON string

\" Makes sure the string is properly terminated

Frankly, you're better off using a real JSON parser, though.

Community
  • 1
  • 1
Parthian Shot
  • 1,390
  • 1
  • 13
  • 24