Chuyển đổi đầu ra của lệnh cây thành định dạng json


10

Có cách nào thuận tiện để chuyển đổi đầu ra của lệnh "cây" nix thành định dạng JSON không?

Chỉnh sửa: Tôi nghĩ rằng tôi đã không mô tả vấn đề của tôi đủ tốt. Mục tiêu của tôi là chuyển đổi một cái gì đó như:

.
|-- dir1
|   |-- dirA
|   |   |-- dirAA
|   |   `-- dirBB
|   `-- dirB
`-- dir2
    |-- dirA
    `-- dirB

vào:

{"dir1" : [{"dirA":["dirAA", "dirAB"]}, "dirB"], "dir2": ["dirA", "dirB"]}

Làm thế nào bạn mong đợi để thấy rằng được gói gọn trong JSON? Bạn có thể cho một ví dụ và kết quả mong đợi?
Drav Sloan

@DravSloan Tôi đã chỉnh sửa bài đăng để hiển thị một ví dụ
roundrobin

Bạn sẽ nhận được gì nếu dir1/dirAcó thư mục con?
cjm

{"dir1" : [{"dirA":["dirAA", "dirAB"]}, "dirB"], "dir2": ["dirA", "dirB"]}
roundrobin

@BausTheBig - Tôi không nghĩ bạn đã nghĩ đến điều này trong suốt chặng đường. Các treelệnh không phải là công cụ thích hợp. Tôi có thể có khuynh hướng làm ls -Rhoặc findthay vào đó.
slm

Câu trả lời:


6

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::Findmô-đun hoạt động theo cách tương tự như findlệnh unix . Các JSONmô-đ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_dircho mỗi tệp / thư mục trong ".", Và no_chdirthô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 %$dirsthành $ref, chia xung quanh đường dẫn tập tin /và vòng lặp với forthê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 :)


Oh định dạng cho thư mục con bây giờ hơi khác một chút, định dạng đầu ra ở trên có phải là một vấn đề không?
Drav Sloan

Vâng, tôi đã tự quay về định dạng đó. Tôi không chắc nó là tiêu chuẩn theo bất kỳ cách nào, không thể tìm thấy nhiều thứ sẽ cung cấp cho nó như vậy, nhưng cách tiếp cận của bạn là một cải tiến rõ ràng.
slm

Có tiến bộ gì với việc này không? 8-)
slm

Tôi đã theo dõi bên với một slm-style-ascii-network-a-gram cho một câu hỏi khác (dừng lại vì câu hỏi này khiến đầu óc tôi quay cuồng). Tôi sẽ làm một tách để điều chỉnh tỷ lệ caffiene / máu của tôi và xem xét lại.
Drav Sloan

asciio là công cụ để tạo ra em
slm

13

Phiên bản 1.7 bao gồm hỗ trợ cho JSON:
http://mama.indstate.edu/users/ice/tree/changes.html

Trên mỗi mantrang (dưới XML/JSON/HTML OPTIONS):

-J     Turn on JSON output. Outputs the directory tree as an JSON formatted array.

ví dụ

$ 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}
]

5

Đây là một cách sử dụng Perl và mô-đun JSON perl.

$ tree | perl -e 'use JSON; @in=grep(s/\n$//, <>); \
     print encode_json(\@in)."\n";'

Thí dụ

Tạo một số dữ liệu mẫu.

$ mkdir -p dir{1..5}/dir{A,B}

Đây là những gì nó trông giống như:

$ tree 
.
|-- dir1
|   |-- dirA
|   `-- dirB
|-- dir2
|   |-- dirA
|   `-- dirB
|-- dir3
|   |-- dirA
|   `-- dirB
|-- dir4
|   |-- dirA
|   `-- dirB
`-- dir5
    |-- dirA
    `-- dirB

15 directories, 0 files

Đây là một lần chạy bằng lệnh Perl:

$ tree | perl -e 'use JSON; @in=grep(s/\n$//, <>); print encode_json(\@in)."\n";'

Trả về kết quả này:

[".","|-- dir1","|   |-- dirA","|   `-- dirB","|-- dir2","|   |-- dirA","|   `-- dirB","|-- dir3","|   |-- dirA","|   `-- dirB","|-- dir4","|   |-- dirA","|   `-- dirB","`-- dir5","    |-- dirA","    `-- dirB","","15 directories, 0 files"]

LƯU Ý: Đây chỉ là sự đóng gói của đầu ra từ tree. Không phải là một hệ thống phân cấp lồng nhau. OP đã thay đổi câu hỏi sau khi tôi đề nghị điều này!


xin lỗi tôi nghĩ rằng tôi đã không mô tả vấn đề của tôi đủ tốt. Mục tiêu của tôi là chuyển đổi một cái gì đó như: | - dir1 | | - dirA | | - dirB | - dir2 | | - dirA | | - dirB vào: {"dir1": ["dirA", "dirB"], "dir2": ["dirA", "dirB"]}
roundrobin

@BausTheBig - không vấn đề gì. Chỉnh sửa câu trả lời của bạn và thêm một ví dụ về những gì bạn muốn.
slm

Cấu trúc dữ liệu mà OP dường như sau khi trông giống như một đối tượng Python. Tôi gần như không có kiến ​​thức về Python vì vậy tôi không thể giúp nhưng tôi đoán loại cấu trúc này dễ xây dựng hơn ở đó.
terdon

@terdon - Tôi đã để nó cho Drav, nó trông giống như cấu trúc Hash of Hashing cho chúng tôi.
slm

2

Tôi cũng đang tìm cách để xuất một cây thư mục / tệp linux sang một số tệp JSON hoặc XML. Tại sao không sử dụng lệnh đầu cuối đơn giản này:

tree --dirsfirst --noreport -n -X -i -s -D -f -o my.xml

Vì vậy, chỉ cần treelệnh Linux và cấu hình các tham số của riêng bạn. Ở đây -Xcung cấp đầu ra XML. Đối với tôi, điều đó ổn và tôi đoán có một số tập lệnh để chuyển đổi XML thành JSON.


1

Bạn có thể thử lệnh này:

tree -a -J -o *filename*

Thay thế tên tệp bằng tên tệp đầu ra mong muốn của bạn.


Không có một lá cờ như vậy Jcho lệnh tree!!

Upvote: trên cây v1.7.0 có cờ J ... chúc mừng
drl

0

Đây là công việc. https://gist.github.com/debodirno/18a21df0511775c19de8d7ccbc99cb72

import os
import sys
import json

def tree_path_json(path):
    dir_structure = {}
    base_name = os.path.basename(os.path.realpath(path))
    if os.path.isdir(path):
        dir_structure[base_name] = [ tree_path_json(os.path.join(path, file_name))\
         for file_name in os.listdir(path) ]
    else:
        return os.path.basename(path)
    return dir_structure

if len(sys.argv) > 1:
    path = sys.argv[1]
else:
    path = '.'

print json.dumps(tree_path_json(path), indent = 4, separators = (', ', ' : '))

Tôi không hiểu điều đó
Pierre.Vriens

Vì vậy, điều này chuyển đổi cấu trúc cây thành json. Chạy mã này trên một thư mục và nó sẽ tạo ra json như được chỉ ra trong câu hỏi.
Debodirno Chandra
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.