트리 명령의 출력을 json 형식으로 변환


10

* nix 명령 "tree"의 출력을 JSON 형식으로 변환하는 편리한 방법이 있습니까?

편집 : 내 문제를 충분히 설명하지 못했다고 생각합니다. 내 목표는 다음과 같은 것을 변환하는 것입니다.

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

으로:

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

JSON으로 캡슐화 된 것을 어떻게 볼 수 있습니까? 예와 예상 결과를 줄 수 있습니까?
Drav Sloan

@DravSloan 예를 보여주기 위해 글을 편집했습니다
roundrobin

dir1/dirA하위 디렉토리 가 있으면 무엇을 얻을 수 있습니까?
CJM

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

@BausTheBig-나는 당신이 이것을 완전히 생각했다고 생각하지 않습니다. 이 tree명령은 올바른 도구가 아닙니다. 나는 ls -R또는 그 find대신에 경향이있을 수 있습니다 .
slm

답변:


6

시도 1

펄만 사용하여 해시 구조의 간단한 해시를 반환하는 솔루션. 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모듈은 unix find명령 과 유사한 방식으로 작동합니다 . 이 JSON모듈은 perl 변수를 가져 와서 JSON으로 변환합니다.

find({wanted => \&process_dir, no_chdir => 1 }, ".");

process_dir"."아래의 각 파일 / 디렉토리에 대한 서브 루틴 을 호출하는 현재 작업 디렉토리에서 파일 구조를 반복 하고 찾은 각 디렉토리에 대해 no_chdira를 발행하지 말라고 지시 chdir()합니다.

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...하지만 스테판은 아직 이것을 보지 못했습니다 :)


서브 디렉토리의 형식이 지금과 약간 다릅니다. 위의 출력 형식이 문제가됩니까?
Drav Sloan

그래, 나는 그 형식을 스스로 돌고있다. 나는 그것이 어떤 식 으로든 표준인지 확신 할 수 없으며 선반에서 그렇게 많이 제공 할 수는 없지만 접근 방식은 확실히 개선되었습니다.
slm

이것으로 어떤 진전이 있습니까? 8-)
slm

나는 또 다른 질문 (이것이 내 머리를 돌리면서 피트 스탑)에 slm-style-ascii-network-a-gram으로 측면을 추적했다. 카피 엔 / 혈액 비율을 수정하고 다시 한 번 컵파를 만들겠습니다.
Drav Sloan

asciio는 em
slm

13

버전 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}
]

5

Perl과 JSON perl 모듈을 사용하는 한 가지 방법이 있습니다.

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

샘플 데이터를 작성하십시오.

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

그 모습은 다음과 같습니다.

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

15 directories, 0 files

Perl 명령을 사용한 실행은 다음과 같습니다.

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

이 출력을 반환합니다 :

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

참고 : 이것은의 출력을 캡슐화 한 것입니다 tree. 중첩 된 계층이 아닙니다. OP가 제안한 후에 ​​질문을 변경했습니다!


미안하지만 내 문제를 충분히 설명하지 못했다고 생각합니다. 내 목표는 다음과 같은 것을 변환하는 것입니다. |-dir1 | |-dirA | |-dirB |-dir2 | |-dirA | |-dirB를 { "dir1": [ "dirA", "dirB"], "dir2": [ "dirA", "dirB"]}
roundrobin

@BausTheBig-문제 없습니다. 답을 수정하고 원하는 예를 추가하십시오.
slm

OP 이후의 데이터 구조는 Python 객체처럼 보입니다. 나는 파이썬에 대한 지식이 거의 없으므로 도울 수 없지만 이런 종류의 구조가 더 쉽게 구축 될 수 있다고 생각합니다.
terdon

@ terdon-나는 그것을 Drav에 맡겼다. 그것은 우리에게 해시 해시 구조처럼 보였다.
slm

2

또한 리눅스 폴더 / 파일 트리를 JSON 또는 XML 파일로 출력하는 방법을 찾고있었습니다. 이 간단한 터미널 명령을 사용하지 않는 이유 :

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

따라서 Linux tree명령 만 사용하고 고유 한 매개 변수를 구성하십시오. 다음 -X은 XML 출력을 제공합니다. 저에게는 괜찮습니다 .XML을 JSON으로 변환하는 스크립트가 있다고 생각합니다.


1

이 명령을 시도해 볼 수 있습니다.

tree -a -J -o *filename*

파일 이름을 원하는 출력 파일 이름으로 바꾸십시오.


J명령에 대한 플래그가 없습니다 tree!!

공감 : 트리 v1.7.0에는 깃발 J가 있습니다 ... 건배
drl

1

이 작업을 수행합니다. 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 = (', ', ' : '))

나는 그것을 얻지 못한다
Pierre.Vriens

1
트리 구조를 json으로 변환합니다. 디렉토리 에서이 코드를 실행하면 질문에 표시된대로 json이 생성됩니다.
Debodirno Chandra
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.