Konversi keluaran perintah pohon ke format json


10

Apakah ada cara mudah untuk mengkonversi output dari perintah * nix "tree" ke format JSON?

Sunting: Saya pikir saya tidak menggambarkan masalah saya dengan cukup baik. Tujuan saya adalah mengonversi sesuatu seperti:

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

ke:

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

Bagaimana Anda berharap melihat itu dienkapsulasi dalam JSON? Bisakah Anda memberikan contoh dan hasil yang diharapkan?
Drav Sloan

@ DravSloan Saya mengedit posting untuk menunjukkan contoh
roundrobin

Apa yang akan Anda dapatkan jika dir1/dirAmemiliki subdirektori?
cjm

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

@BausTheBig - Saya tidak berpikir Anda telah memikirkan ini sepanjang jalan. The treeperintah bukanlah alat yang tepat. Saya mungkin cenderung melakukan ls -Ratau findsebaliknya.
slm

Jawaban:


6

Percobaan 1

Sebuah solusi menggunakan hanya perl, mengembalikan hash struktur hash sederhana. Sebelum OP mengklarifikasi format data 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::Findmodul bekerja dengan cara yang mirip dengan findperintah unix . The JSONModul mengambil variabel perl dan bertobat mereka ke JSON.

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

Akan mengulangi struktur file dari direktori kerja sekarang memanggil subrutin process_diruntuk setiap file / direktori di bawah ".", Dan no_chdirkirim perl untuk tidak mengeluarkan chdir()untuk setiap direktori yang ditemukannya.

process_dir kembali jika file yang diperiksa bukan direktori:

return if !-d $File::Find::name;

Kami kemudian mengambil referensi dari hash yang ada %$dirske dalam $ref, membagi jalur file di sekitar /dan loop dengan formenambahkan kunci hash baru untuk setiap jalur.

Membuat struktur direktori seperti slm lakukan:

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

Outputnya adalah:

{
   "." : {
      "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" : {}
         }
      }
   }
}

Percobaan 2

Oke sekarang dengan struktur data yang berbeda ...

#! /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
}

Dan kemudian menjalankan skrip pada struktur direktori yang diusulkan ...

./tree2json2.pl .
{
   "dir2" : [
      "dirB",
      "dirA"
   ],
   "dir1" : [
      "dirB",
      {
         "dirA" : [
            "dirBB",
            "dirAA"
         ]
      }
   ]
}

Saya menemukan ini sangat sulit untuk mendapatkan yang benar (terutama mengingat "hash if sub directories, array if not, OH UNLESS top level, maka hash anyway" logika). Jadi saya akan terkejut jika ini adalah sesuatu yang dapat Anda lakukan dengan sed/ awk... tapi kemudian Stephane belum melihat ini, saya yakin :)


Oh format untuk subdirektori agak berbeda sekarang, apakah format output di atas akan menjadi masalah?
Drav Sloan

Ya saya sendiri sudah memutar format itu sendiri. Saya tidak yakin itu standar dalam bentuk apa pun, tidak dapat menemukan banyak dari rak yang akan menyediakannya seperti itu, tetapi pendekatan Anda adalah peningkatan yang pasti.
slm

Membuat kemajuan dengan ini? 8-)
slm

Saya mendapat sisi dilacak dengan slm-style-ascii-network-a-gram pada pertanyaan lain (pit stop karena ini membuat kepala saya berputar). Saya akan membuat secangkir teh untuk memperbaiki rasio caffiene / darah saya dan melihat lagi.
Drav Sloan

asciio adalah alat untuk membuat em
slm

13

Versi 1.7 termasuk dukungan untuk JSON:
http://mama.indstate.edu/users/ice/tree/changes.html

Per manhalaman (di bawah XML/JSON/HTML OPTIONS):

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

misalnya

$ 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

Berikut adalah salah satu cara menggunakan Perl dan modul perl JSON.

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

Contoh

Buat beberapa data sampel.

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

Begini tampilannya:

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

15 directories, 0 files

Berikut ini adalah menjalankan menggunakan perintah Perl:

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

Yang mengembalikan hasil ini:

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

CATATAN: Ini hanya enkapsulasi dari output dari tree. Bukan hierarki bersarang. OP mengubah pertanyaan setelah saya menyarankan ini!


maaf saya pikir saya tidak menggambarkan masalah saya dengan cukup baik. Tujuan saya adalah mengonversi sesuatu seperti: | - dir1 | | - dirA | | - dirB | - dir2 | | - dirA | | - dirB ke: {"dir1": ["dirA", "dirB"], "dir2": ["dirA", "dirB"]}
roundrobin

@BausTheBig - tidak ada masalah. Edit jawaban Anda dan tambahkan contoh dari apa yang Anda inginkan.
slm

Struktur data OP tampaknya setelah terlihat seperti objek Python. Saya hampir tidak memiliki pengetahuan tentang Python jadi saya tidak dapat membantu tetapi saya kira struktur seperti ini lebih mudah untuk dibangun di sana.
terdon

@terdon - Saya menyerahkannya pada Drav, itu tampak seperti struktur Hash of Hash kepada kami.
slm

2

Saya juga mencari cara untuk mengeluarkan folder linux / pohon file ke beberapa file JSON atau XML. Mengapa tidak menggunakan perintah terminal sederhana ini:

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

Jadi, cukup treeperintah Linux , dan konfigurasikan parameter Anda sendiri. Di sini -Xmemberikan output XML. Bagi saya, tidak apa-apa, dan saya kira ada beberapa skrip untuk mengkonversi XML ke JSON.


1

Anda dapat mencoba perintah ini:

tree -a -J -o *filename*

Ganti nama file dengan nama file output yang Anda inginkan.


Tidak ada bendera Juntuk perintah tree!!

Suara positif: pada pohon v1.7.0 ada bendera J ... tepuk tangan
drl

0

Ini berhasil. 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 = (', ', ' : '))

Saya tidak mengerti
Pierre.Vriens

Jadi ini mengubah struktur pohon menjadi json. Jalankan kode ini pada direktori dan itu akan menghasilkan json seperti yang ditunjukkan dalam pertanyaan.
Debodirno Chandra
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.