Text-Processing
將 tree 命令的輸出轉換為 json 格式
有沒有一種方便的方法可以將 *nix 命令“tree”的輸出轉換為 JSON 格式?
編輯: 我認為我沒有很好地描述我的問題。我的目標是轉換如下內容:
. |-- dir1 | |-- dirA | | |-- dirAA | | `-- dirBB | `-- dirB `-- dir2 |-- dirA `-- dirB
進入:
{"dir1" : [{"dirA":["dirAA", "dirAB"]}, "dirB"], "dir2": ["dirA", "dirB"]}
嘗試 1
僅使用 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->{$_}; } }
File::Find
module 的工作方式與 unixfind
命令類似。該JSON
模組採用 perl 變數並將它們轉換為 JSON。find({wanted => \&process_dir, no_chdir => 1 }, ".");
將從目前工作目錄向下迭代文件結構,
process_dir
為“.”下的每個文件/目錄呼叫子常式,並no_chdir
告訴 perl 不要為它找到的每個目錄發出 achdir()
。
process_dir
如果目前檢查的文件不是目錄,則返回:return if !-d $File::Find::name;
然後,我們將現有雜湊的引用抓取
%$dirs
到中$ref
,將文件路徑拆分/
並循環,for
為每個路徑添加一個新的雜湊鍵。製作像 slm 這樣的目錄結構:
mkdir -p dir{1..5}/dir{A,B}/subdir{1..3}
輸出是:
{ "." : { "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" : {} } } } }
嘗試 2
好的,現在使用不同的資料結構……
#! /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 }
然後在建議的目錄結構上執行腳本……
./tree2json2.pl . { "dir2" : [ "dirB", "dirA" ], "dir1" : [ "dirB", { "dirA" : [ "dirBB", "dirAA" ] } ] }
我發現這非常棘手(特別是考慮到“如果子目錄雜湊,如果不是數組,哦,除非頂層,然後只是雜湊”邏輯)。所以如果這是你可以用
sed
/做的事情,我會感到驚訝awk
……但是斯蒂芬還沒有看過這個我敢打賭:)
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.
例如
$ 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} ]