1

I have some JSON data:

    "Item1": {
      "foo": null,
      "version": "bar",
      "result": null,
    },
    "Item2": {
      "foo": null,
      "version": "bar",
      "result": null,
    },
    "Item3": {
      "foo": null,
      "version": "bar",
      "result": null,
    },

With awk I'm able to filter strings:

$ awk '/version/' /tmp/json
      "version": "bar",
      "version": "bar",
      "version": "bar",

I'm trying to count the number of lines and get the following result without piping, pure awk.

$ awk '/version/' /tmp/json | wc -l
3

Examples online show how to use END and NR but this doesn't produce the results I'm looking for:

$ awk '/version/{print NR}' /tmp/json
3
8
13

or

$ awk 'END/version/{print NR}' /tmp/json
awk: line 1: syntax error at or near /version/
1
  • 1
    Why aren't you using a JSON parser like jq for this?
    – Ed Morton
    Commented Aug 6, 2020 at 21:50

2 Answers 2

4

If you really insist on doing this in awk, all you need to do is increment a variable for each matching line and then, once all lines have been processed, print that variable:

$ awk '/version/{c++}END{print c}' file
3

Or, if you want to get a 0 printed when there are no matches (the above will just print an empty line), use:

awk '/version/{c++}END{print c+0}' file

Finally to print only if there is at least one match (so no output, instead of an empty line, when there are no matches), use:

awk '/version/{c++}END{ if(c) print c}' 
3
  • @edmorton I saw you used the +0 in a comment as well, but what's the point of it here? The variable is only ever going to have numerical values, it is exclusively used in c++ and then in print c so this can't be as a safety net to make sure it's a number. As it stands, this just causes it to print a useless 0 when there are no matches. I find it much more practical to have no output when there are no matches.
    – terdon
    Commented Aug 7, 2020 at 13:58
  • The original script will output a blank line, not no output, when there are no matches. If version never appears in the input then in the END section c will never have been incremented or even set and so it'll still have the value zero-or-null and be printed as null unless you force it to be a number by adding 0. If you like having no output in that scenario (which I can definitely understand) then make it if (c) print c instead but grep -c 'version' would output 0 in that case and IMHO that makes sense and it's worth replicating the behavior here.
    – Ed Morton
    Commented Aug 7, 2020 at 14:06
  • 1
    @EdMorton I see, yes. Fair enough, thanks.
    – terdon
    Commented Aug 7, 2020 at 14:09
0
awk 'BEGIN { count=0 } /version/ { count++ } END { printf( "%d\n", count ) }' datafile.json

But, more simply:

grep -c 'version' datafile.json
4
  • 1
    The awk code doesn't need to be that lengthy: awk '/version/{c++} END{print c+0}'
    – Ed Morton
    Commented Aug 6, 2020 at 21:49
  • @EdMorton: why the +0 ¿? Is this to enforce numeric type ?
    – Cbhihe
    Commented Aug 7, 2020 at 7:35
  • @Cbhihe it ensures you get a number 0 output instead of a null string when there are no versions in the input.
    – Ed Morton
    Commented Aug 7, 2020 at 13:53
  • It does not need to be that lengthy, but I generally write more bellicose code on venues such as this in the interest of making the intent and logic clear rather than short. (Also, +0 is no longer necessary when the value is initialized as in the code presented in my answer)
    – DopeGhoti
    Commented Aug 10, 2020 at 14:07

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.