rou*_*bin 11 text-processing tree json
有没有一种方便的方法可以将 *nix 命令“tree”的输出转换为 JSON 格式?
编辑: 我想我没有很好地描述我的问题。我的目标是转换如下内容:
.
|-- dir1
| |-- dirA
| | |-- dirAA
| | `-- dirBB
| `-- dirB
`-- dir2
|-- dirA
`-- dirB
Run Code Online (Sandbox Code Playgroud)
进入:
{"dir1" : [{"dirA":["dirAA", "dirAB"]}, "dirB"], "dir2": ["dirA", "dirB"]}
Run Code Online (Sandbox Code Playgroud)
Sri*_*bat 18
1.7 版包括对 JSON 的支持:http :
//mama.indstate.edu/users/ice/tree/changes.html
每页man(在 下XML/JSON/HTML OPTIONS):
-J Turn on JSON output. Outputs the directory tree as an JSON formatted array.
Run Code Online (Sandbox Code Playgroud)
例如
$ tree -J
/home/me/trash/tree-1.7.0
[{"type":"directory","name": ".","contents":[
{"type":"file","name":"CHANGES"},
{"type":"file","name":"color.c"},
{"type":"file","name":"color.o"},
{"type":"directory","name":"doc","contents":[
{"type":"file","name":"tree.1"},
{"type":"file","name":"tree.1.fr"},
{"type":"file","name":"xml.dtd"}
]},
{"type":"file","name":"hash.c"},
{"type":"file","name":"hash.o"},
{"type":"file","name":"html.c"},
{"type":"file","name":"html.o"},
{"type":"file","name":"INSTALL"},
{"type":"file","name":"json.c"},
{"type":"file","name":"json.o"},
{"type":"file","name":"LICENSE"},
{"type":"file","name":"Makefile"},
{"type":"file","name":"README"},
{"type":"file","name":"strverscmp.c"},
{"type":"file","name":"TODO"},
{"type":"file","name":"tree"},
{"type":"file","name":"tree.c"},
{"type":"file","name":"tree.h"},
{"type":"file","name":"tree.o"},
{"type":"file","name":"unix.c"},
{"type":"file","name":"unix.o"},
{"type":"file","name":"xml.c"},
{"type":"file","name":"xml.o"}
]},
{"type":"report","directories":1,"files":26}
]
Run Code Online (Sandbox Code Playgroud)
仅使用 perl 的解决方案,返回哈希结构的简单哈希。在 OP 阐明 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->{$_};
}
}
Run Code Online (Sandbox Code Playgroud)
File::Find模块的工作方式与 unixfind命令类似。该JSON模块采用 perl 变量并将它们转换为 JSON。
find({wanted => \&process_dir, no_chdir => 1 }, ".");
Run Code Online (Sandbox Code Playgroud)
将从当前工作目录向下迭代文件结构,process_dir为“.”下的每个文件/目录调用子例程,并no_chdir告诉 perl 不要为chdir()它找到的每个目录发出 a 。
process_dir 如果当前检查的文件不是目录,则返回:
return if !-d $File::Find::name;
Run Code Online (Sandbox Code Playgroud)
然后我们将现有散列的引用抓取%$dirs到 中$ref,拆分文件路径/并循环,for为每个路径添加一个新的散列键。
制作像 slm 那样的目录结构:
mkdir -p dir{1..5}/dir{A,B}/subdir{1..3}
Run Code Online (Sandbox Code Playgroud)
输出是:
{
"." : {
"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" : {}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
好的,现在使用不同的数据结构......
#! /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
}
Run Code Online (Sandbox Code Playgroud)
然后在建议的目录结构上运行脚本......
./tree2json2.pl .
{
"dir2" : [
"dirB",
"dirA"
],
"dir1" : [
"dirB",
{
"dirA" : [
"dirBB",
"dirAA"
]
}
]
}
Run Code Online (Sandbox Code Playgroud)
我发现这非常棘手(特别是考虑到“如果子目录是哈希,如果不是数组,哦,除非顶级,那么无论如何都只是哈希”逻辑)。所以,如果这是你可以用sed/做的事情,我会感到惊讶awk……但我敢打赌,斯蒂芬还没有看过这个:)
这是使用 Perl 和 JSON perl 模块的一种方法。
$ tree | perl -e 'use JSON; @in=grep(s/\n$//, <>); \
print encode_json(\@in)."\n";'
Run Code Online (Sandbox Code Playgroud)
创建一些示例数据。
$ mkdir -p dir{1..5}/dir{A,B}
Run Code Online (Sandbox Code Playgroud)
这是它的样子:
$ tree
.
|-- dir1
| |-- dirA
| `-- dirB
|-- dir2
| |-- dirA
| `-- dirB
|-- dir3
| |-- dirA
| `-- dirB
|-- dir4
| |-- dirA
| `-- dirB
`-- dir5
|-- dirA
`-- dirB
15 directories, 0 files
Run Code Online (Sandbox Code Playgroud)
这是使用 Perl 命令的运行:
$ tree | perl -e 'use JSON; @in=grep(s/\n$//, <>); print encode_json(\@in)."\n";'
Run Code Online (Sandbox Code Playgroud)
返回此输出:
[".","|-- dir1","| |-- dirA","| `-- dirB","|-- dir2","| |-- dirA","| `-- dirB","|-- dir3","| |-- dirA","| `-- dirB","|-- dir4","| |-- dirA","| `-- dirB","`-- dir5"," |-- dirA"," `-- dirB","","15 directories, 0 files"]
Run Code Online (Sandbox Code Playgroud)
注意:这只是tree. 不是嵌套层次结构。在我提出这个建议后,OP 改变了这个问题!
| 归档时间: |
|
| 查看次数: |
13119 次 |
| 最近记录: |