แปลงเอาต์พุตของคำสั่ง tree เป็นรูปแบบ 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

@BausTheBig - ฉันไม่คิดว่าคุณจะคิดอย่างนี้ตลอดทาง treeคำสั่งไม่ได้เป็นเครื่องมือที่เหมาะสม ฉันอาจมีแนวโน้มที่จะทำls -Rหรือfindแทน
slm

คำตอบ:


6

พยายาม 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โมดูลทำงานในลักษณะคล้ายกับfindคำสั่งunix JSONโมดูลใช้เวลาตัวแปร Perl และแปลงให้เป็น JSON

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

จะทำซ้ำโครงสร้างของไฟล์จากไดเร็กทอรีการทำงานปัจจุบันที่เรียกรูทีนย่อยprocess_dirสำหรับแต่ละไฟล์ / ไดเร็กทอรีภายใต้ "." และคำสั่งno_chdirperl จะไม่ออก a 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"
         ]
      }
   ]
}

ฉันพบว่ามันช่างน่ากลัวที่จะได้รับสิ่งที่ถูกต้อง (โดยเฉพาะอย่างยิ่งเมื่อได้รับ "แฮ็กถ้าไดเรกทอรีย่อย, อาร์เรย์ถ้าไม่ใช่, OH UNLESS ระดับบนสุด, แล้วแค่แฮชต่อไป" ตรรกะ) ดังนั้นฉันจะแปลกใจถ้านี่เป็นสิ่งที่คุณสามารถทำได้ด้วยsed/ awk... แต่แล้วสเตฟานยังไม่ได้ดูสิ่งนี้ แต่ฉันเดิมพัน :)


โอ้รูปแบบสำหรับ dirs ย่อยแตกต่างกันบ้างในขณะนี้รูปแบบผลลัพธ์ข้างต้นจะเป็นปัญหาหรือไม่
Drav Sloan

ใช่ฉันได้ปั่นในรูปแบบนั้นเอง ฉันไม่แน่ใจว่ามันเป็นมาตรฐานในรูปแบบใดไม่สามารถหาชั้นวางที่จะให้มันได้ แต่แนวทางของคุณคือการปรับปรุงที่ชัดเจน
slm

มีความคืบหน้าเกี่ยวกับเรื่องนี้หรือไม่? 8-)
slm

ฉันได้รับการติดตามด้านด้วย slm-style-ascii-network-a-gram ในคำถามอื่น (หยุดพิทเนื่องจากสิ่งนี้ทำให้หัวของฉันหมุน) ฉันจะทำ cuppa เพื่อแก้ไขอัตราส่วน caffiene / blood ของฉันแล้วดูอีกครั้ง
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 และโมดูล Perl per JSON

$ 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 | | - Díra | | - dirB เข้าสู่: {"dir1": ["dirA", "dirB"], "dir2": ["dirA", "dirB"]}
roundrobin

@BausTheBig - ไม่มีปัญหา แก้ไขคำตอบของคุณและเพิ่มตัวอย่างของสิ่งที่คุณต้องการ
slm

โครงสร้างข้อมูล OP ดูเหมือนว่าจะเป็นวัตถุ Python ฉันแทบไม่มีความรู้เกี่ยวกับ Python ดังนั้นฉันจึงอดไม่ได้ที่จะคาดเดาว่าโครงสร้างประเภทนี้จะสร้างได้ง่ายกว่านี้
terdon

@terdon - ฉันทิ้งมันไว้ที่ Drav ดูเหมือนว่าโครงสร้างของ Hash of Hashes สำหรับพวกเรา
slm

2

ฉันยังค้นหาวิธีที่จะส่งออกต้นไม้ / ไฟล์ลินุกซ์ไปยังไฟล์ JSON หรือ XML บางไฟล์ ทำไมไม่ใช้คำสั่ง terminal ง่ายๆนี้:

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

ดังนั้นเพียงแค่treeคำสั่งLinux และกำหนดค่าพารามิเตอร์ของคุณเอง ที่นี่-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.