Cố gắng 1
Một giải pháp chỉ sử dụng perl, trả về một hàm băm đơn giản của cấu trúc băm. Trước khi OP làm rõ định dạng dữ liệu của JSON.
#! /usr/bin/perl
use 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
mô-đun hoạt động theo cách tương tự như find
lệnh unix . Các JSON
mô-đun có biến perl và chuyển đổi chúng thành JSON.
find({wanted => \&process_dir, no_chdir => 1 }, ".");
Sẽ lặp lại cấu trúc tệp từ thư mục làm việc hiện tại gọi chương trình con process_dir
cho mỗi tệp / thư mục trong ".", Và no_chdir
thông báo perl không phát hành chdir()
cho mỗi thư mục mà nó tìm thấy.
process_dir
trả về nếu tệp được kiểm tra hiện tại không phải là một thư mục:
return if !-d $File::Find::name;
Sau đó chúng tôi lấy một tài liệu tham khảo của các hash hiện %$dirs
thành $ref
, chia xung quanh đường dẫn tập tin /
và vòng lặp với for
thêm một chìa khóa băm mới cho mỗi con đường.
Tạo cấu trúc thư mục như slm đã làm:
mkdir -p dir{1..5}/dir{A,B}/subdir{1..3}
Đầu ra là:
{
"." : {
"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" : {}
}
}
}
}
Cố gắng 2
Được rồi với cấu trúc dữ liệu khác nhau ...
#! /usr/bin/perl
use warnings;
use strict;
use JSON;
my $encoder = JSON->new->ascii->pretty; # ascii character set, pretty format
my $dirs; # used to build the data structure
my $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 @dirs
opendir(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 structure
print $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
}
Và sau đó chạy tập lệnh trên cấu trúc thư mục được đề xuất ...
./tree2json2.pl .
{
"dir2" : [
"dirB",
"dirA"
],
"dir1" : [
"dirB",
{
"dirA" : [
"dirBB",
"dirAA"
]
}
]
}
Tôi thấy điều này khá khó khăn để hiểu đúng (đặc biệt là được đưa ra "hàm băm nếu thư mục con, mảng nếu không, OH UNLESS cấp cao nhất, sau đó chỉ cần băm logic"). Vì vậy, tôi sẽ rất ngạc nhiên nếu đây là điều bạn có thể làm với sed
/ awk
... nhưng sau đó Stephane vẫn chưa xem xét điều này tôi đặt cược :)