Is there a convenient way to convert the output of the *nix command tree to JSON format?Edit:I think I didn't describe my problem well enough. My goal is to convert something like: .|-- dir1|   |-- dirA|   |   |-- dirAA|   |   `-- dirBB|   `-- dirB`-- dir2    |-- dirA    `-- dirBinto: {dir1 : [{dirA:[dirAA, dirAB]}, dirB], dir2: [dirA, dirB]}
Convert output of tree command to json format
text processing;tree;json
Attempt 1A solution using just perl, returning a simple hash of hashes structure. Before theOP clarified data format of JSON.#! /usr/bin/perluse File::Find;use JSON;use strict;use warnings;my $dirs={};my $encoder = JSON->new->ascii->pretty;find({wanted => \&process_dir, no_chdir => 1 }, .);print $encoder->encode($dirs);sub process_dir {    return if !-d $File::Find::name;    my $ref=\%$dirs;    for(split(/\//, $File::Find::name)) {        $ref->{$_} = {} if(!exists $ref->{$_});        $ref = $ref->{$_};    }}File::Find module works in a similar way to the unix find command. The JSON module takes perl variables and converts them into JSON. find({wanted => \&process_dir, no_chdir => 1 }, .);Will iterate down the file structure from the present working directory calling the subroutine process_dir for each file/directory under ., and the no_chdir tell perl not to issue a chdir() for each directory it finds. process_dir returns if the present examined file is not a directory:return if !-d $File::Find::name;We then grab a reference of the existing hash %$dirs into $ref, split the file path around / and loop with for adding a new hash key for each path. Making a directory structure like slm did:mkdir -p dir{1..5}/dir{A,B}/subdir{1..3}The output is:{   . : {      dir3 : {         dirA : {            subdir2 : {},            subdir3 : {},            subdir1 : {}         },         dirB : {            subdir2 : {},            subdir3 : {},            subdir1 : {}         }      },      dir2 : {         dirA : {            subdir2 : {},            subdir3 : {},            subdir1 : {}         },         dirB : {            subdir2 : {},            subdir3 : {},            subdir1 : {}         }      },      dir5 : {         dirA : {            subdir2 : {},            subdir3 : {},            subdir1 : {}         },         dirB : {            subdir2 : {},            subdir3 : {},            subdir1 : {}         }      },      dir1 : {         dirA : {            subdir2 : {},            subdir3 : {},            subdir1 : {}         },         dirB : {            subdir2 : {},            subdir3 : {},            subdir1 : {}         }      },      dir4 : {         dirA : {            subdir2 : {},            subdir3 : {},            subdir1 : {}         },         dirB : {            subdir2 : {},            subdir3 : {},            subdir1 : {}         }      }   }}Attempt 2Okay now with different data structure...#! /usr/bin/perluse warnings;use strict;use JSON;my $encoder = JSON->new->ascii->pretty;   # ascii character set, pretty formatmy $dirs;                                 # used to build the data structuremy $path=$ARGV[0] || '.';                 # use the command line arg or working dir# Open the directory, read in the file list, grep out directories and skip '.' and '..'# and assign to @dirsopendir(my $dh, $path) or die can't opendir $path: $!;my @dirs = grep { ! /^[.]{1,2}/ && -d $path/$_ } readdir($dh);closedir($dh);# recurse the top level sub directories with the parse_dir subroutine, returning# a hash reference.%$dirs = map { $_ => parse_dir($path/$_) } @dirs;# print out the JSON encoding of this data structureprint $encoder->encode($dirs);sub parse_dir {    my $path = shift;    # the dir we're working on    # get all sub directories (similar to above opendir/readdir calls)    opendir(my $dh, $path) or die can't opendir $path: $!;    my @dirs = grep { ! /^[.]{1,2}/ && -d $path/$_ } readdir($dh);    closedir($dh);    return undef if !scalar @dirs; # nothing to do here, directory empty    my $vals = [];                            # set our result to an empty array    foreach my $dir (@dirs) {                 # loop the sub directories                 my $res = parse_dir($path/$dir);    # recurse down each path and get results        # does the returned value have a result, and is that result an array of at         # least one element, then add these results to our $vals anonymous array         # wrapped in a anonymous hash        # ELSE        # push just the name of that directory our $vals anonymous array        push(@$vals, (defined $res and scalar @$res) ? { $dir => $res } : $dir);    }    return $vals;  # return the recursed result}And then running the script on the proposed directory structure..../tree2json2.pl .{   dir2 : [      dirB,      dirA   ],   dir1 : [      dirB,      {         dirA : [            dirBB,            dirAA         ]      }   ]}I found this pretty damn tricky to get right (especially given the hash if sub directories, array if not, OH UNLESS top level, then just hashes anyway logic). SoI'd be surprised if this was something you could do with sed / awk ... but thenStephane hasn't looked at this yet I bet :)