Creating a JSON object with name of the JSON file and its content in bash

Viewed 714

I have a few .json files in my directory. If I do:

find . -name '*.json' -exec echo "{\"filename\": \"{}\", \"content\": `cat {}` }," \;

I get:

{"filename": "./a.json", "content":  },
{"filename": "./b.json", "content":  },

However, if I do:

find . -name '*.json' -exec echo "{\"filename\": \"{}\", \"content\": cat {} }," \;

I get:

{"filename": "./a.json", "content": cat ./a.json },
{"filename": "./b.json", "content": cat ./b.json },

so how do I make the a.json and b.json contents be cated correctly ?

BTW, if I do:

find . -name '*.json' -exec cat {} \;

the json files are correctly printed in the console, so I know that the file contents are valid.

2 Answers

Using bash without find you can do below. You can use nullglob and globstar for recursive JSON file name traversal

shopt -s nullglob globstar

By default jq provides a function input_filename which prints the filename being processed currently. The documentation says, it should work fine as long as the locale is UTF-8

jq '{ filename: input_filename, content: . }' **/*.json

To have a comma between the object entries, use the -n flag with inputs and put the entire result in an array [..]

jq -n '[inputs | { filename: input_filename, content: . }]' **/*.json

For compact output on the same line, use the -c flag as jq -c '..'

With simple :

$ cat a.json
{ "a":123 }
$ cat b.json
{ "b":234 }
$ cat "foo/bar/base/c c.json"
{ "c": 456 }
$ shopt -s globstar # enable recursion with '**'
$ for i in **/*.json; do
    cat<<EOF
    { "filename": "$i", "content": $(cat "$i") }
EOF
done | tee file.json
$ cat file.json
{ "filename": "a.json", "content": {"a":123} }
{ "filename": "b.json", "content": {"b":234} }
{ "filename": "foo/bar/base/c c.json", "content": { "c": 456 } }
Related