Home > Software design >  get files from directory in bash and build JSON object using jq
get files from directory in bash and build JSON object using jq

Time:10-11

I am trying to build list of JSON objects with the files in a particular directory. I am looping thru the files and creating the expected output object as string. I am sure there is a better way of doing this using jq.

Can someone please help me out here?

# input
files=($( ls * )) 
prefix="myawesomeprefix"
# expected output

{
  "listoffiles": [
    {"file":"myawesomeprefix/file1.txt"},
    {"file":"myawesomeprefix/file2.txt"},
    {"file":"myawesomeprefix/file3.txt"},
 ]
}

CodePudding user response:

You shouldn't parse the output of ls. If installed, you could use tree with the -J option to produce a JSON listing, which you can transform to your needs using jq:

tree -aJL 1 | jq '
  {listoffiles: first.contents | map({file: ("myawesomeprefix/"   .name)})}
'

Or more comfortably using --arg:

tree -aJL 1 | jq --arg prefix myawesomeprefix '
  {listoffiles: first.contents | map({file: "\($prefix)/\(.name)"})}
'

CodePudding user response:

This is another alternative :

jq -n --arg prefix "myawesomeprefix"\
    '.listoffiles = ($ARGS.positional |
                     map({file:($prefix "/" .)}))'\
    --args *

CodePudding user response:

You can try the nice little command line tool jc:

ls -l | jc --ls

It converts the output of many shell commands to JSON. For reference have a look there in Github https://github.com/kellyjonbrazil/jc .

Then you can transform the result using jq.

CodePudding user response:

If you don't have any "problematic" file names, e.g. ones that have new lines as part of their name, the following should work:

ls -1 | jq -Rn '{ listoffiles: [inputs | { file: "prefix/\(.)" }] }'

It reads each line as string, and reads them through the inputs filter (must be combined with -n null-input). It then builds your object.

$ cat <<LS | jq -Rn '{ listoffiles: [inputs | {file:"prefix/\(.)"}] }'
file1
file2
file with spaces
LS
{
  "listoffiles": [
    {
      "file": "prefix/file1"
    },
    {
      "file": "prefix/file2"
    },
    {
      "file": "prefix/file with spaces"
    }
  ]
}

You could use for with a glob which should handle new lines in file names as well. But it requires you to chain 2 jq commands:

for f in *; do
  printf '%s' "$f" | jq -Rs '{file:"prefix/\(.)"}';
done | jq -s '{listoffiles:.}'

To specify the prefix as variable from the outside, use --var, e.g.

jq --var prefix "yourprefixvalue" '$prefix   .'
  • Related