Detect invalid JSON files in directory tree
I want to fail a build if the directory tree contains a JSON file which is invalid according to the jsonlint
package from NPM.
I thought this would be as easy as running:
find . -name \*.json | xargs jsonlint -q
I knew I had a badly formed JSON document on the disk, and this doesn't pick it up.
Further investigation shows that the find
command works as expected, however the jsonlint
executable is only being called once (and the first JSON file is correct.)
Is there a better way to do this, or is there something I need to learn about xargs
here?
I'm running Ubuntu 13.10 Server and can install packages if needed.
Solution 1:
It looks like jsonlint
cannot deal with multiple files:
$ jsonlint -h
Usage: jsonlint [file] [options]
file file to parse; otherwise uses stdin
Note that it always says file, never files. When you run a command and pipe its output to xargs
as you have done, xargs
will simply concatenate all the output of the command and pass it as input to whatever you have told it to execute. For example:
$ printf "foo\nbar\nbaz\n"
foo
bar
baz
$ printf "foo\nbar\nbaz\n" | xargs echo
foo bar baz
That shows you that the command executed by xargs
was
echo foo bar baz
In the case of jsonlint
, what you want to do is not jsonlint -q foo bar baz
but
$ jsonlint -q foo
$ jsonlint -q bar
$ jsonlint -q baz
The easiest way to do this is to use find
as suggested by @fede.evol:
$ find . -name \*.json -exec xargs jsonlint -q {} \;
To do it with xargs
you need to use the -I
flag:
-I replace-str
Replace occurrences of replace-str in the initial-arguments with
names read from standard input. Also, unquoted blanks do not
terminate input items; instead the separator is the newline
character. Implies -x and -L 1.
For example:
$ find . -name \*.json | xargs -I {} jsonlint -q {}
Or, to deal with strange names (that contain newlines for example) safely:
$ find . -name \*.json -print0 | xargs -0I {} jsonlint -q '{}'
Solution 2:
The current answers to this question are incomplete since the suggested commands will not print the name of the invalid file. Also, jsonlint is one hell of a slow tool.
Here's a much much faster alternative which shouldn't require additional installations on most systems:
find . -name \*.json -exec echo {} \; -exec python -mjson.tool "{}" \; 2>&1 | grep "No JSON" -B 1