Ağaç komutunun çıktısını json formatına dönüştürme


10

* Nix "ağaç" komutunun çıktısını JSON formatına dönüştürmenin uygun bir yolu var mı?

Düzenleme: Bence sorunumu yeterince açıklamamıştım. Amacım şöyle bir şeyi dönüştürmek:

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

içine:

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

Bunun JSON'da kapsüllendiğini nasıl görmeyi beklersiniz? Bir örnek ve beklenen sonuçları verebilir misiniz?
Drav Sloan

@DravSloan Bir örnek göstermek için yayını düzenledim
roundrobin

dir1/dirAAlt dizinleriniz olsaydı ne elde etmeyi beklersiniz ?
cjm

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

@BausTheBig - Bunu sonuna kadar düşündüğünü sanmıyorum. treeKomut doğru aracı değil. Bunu yapmaya meyilli olabilirim ls -Rya da findonun yerine.
slm

Yanıtlar:


6

Deneme 1

Sadece perl kullanan ve hashes yapısının basit bir karma değerini döndüren bir çözüm. OP önce JSON veri formatını açıkladı.

#! /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::Findmodülü unix findkomutuna benzer şekilde çalışır . JSONModül JSON içine perl değişkenleri ve dönüşürse onları alır.

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

process_dir"." Altındaki her dosya / dizin için alt rutini çağıran mevcut çalışma dizininden dosya yapısını yineleyecek ve no_chdirtell perl chdir()bulduğu her dizin için bir a vermeyecektir .

process_dir incelenen mevcut dosya bir dizin değilse döndürür:

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

Daha sonra mevcut karma bir referans kapmak %$dirsiçine $ref, dosya yolu etrafta bölünmüş /olan ve döngü forher yolu için yeni bir karma anahtarı ekleyerek.

Slm gibi bir dizin yapısı yapmak:

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

Çıktı:

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

Deneme 2

Tamam şimdi farklı veri yapısı ile ...

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

Ve sonra komut dosyasını önerilen dizin yapısında çalıştırın ...

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

Ben doğru almak için bu oldukça lanet zor buldum (özellikle "alt dizinleri karma varsa, dizi değilse, OH UNLESS üst düzey, sonra sadece hashes zaten" mantık verilen). Bu, sed/ ile yapabileceğiniz bir şey olsaydı awkşaşırırdım ama sonra Stephane henüz buna bakmadı :)


Oh alt dizinlerin biçimi şimdi biraz farklı, yukarıdaki çıktı biçimi bir sorun olacak mı?
Drav Sloan

Evet, bu formatta kendim dönüyorum. Herhangi bir şekilde standart olduğundan emin değilim, bunu sağlayacak şekilde raftan fazla bulamıyorum, ancak yaklaşımınız kesin bir gelişmedir.
slm

Bununla ilerleme kaydediliyor mu? 8-)
slm

Başka bir soru üzerinde bir slm tarzı-ascii-ağ-a-gram ile yan iz var (pit stop bu bir başımı spin yapıyor gibi). Caffiene / kan oranımı düzeltmek için bir cuppa yapacağım ve bir kez daha bakacağım.
Drav Sloan

asciio em
slm

14

Sürüm 1.7, JSON için destek içerir:
http://mama.indstate.edu/users/ice/tree/changes.html

manSayfa başına (altında XML/JSON/HTML OPTIONS):

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

Örneğin

$ 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

İşte Perl ve JSON perl modülünü kullanmanın bir yolu.

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

Misal

Bazı örnek veriler oluşturun.

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

İşte böyle görünüyor:

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

15 directories, 0 files

İşte Perl komutunu kullanan bir çalışma:

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

Bu çıktıyı döndüren:

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

NOT: Bu sadece çıktısının bir kapsüllenmesidir tree. İç içe bir hiyerarşi değil. Bunu önerdikten sonra OP soruyu değiştirdi!


Üzgünüm, sorunumu yeterince iyi tanımlayamadığımı düşünüyorum. Amacım şöyle bir şey dönüştürmek: | - dir1 | | - dirA | | - dirB | - dir2 | | - dirA | | - dirB içine: {"dir1": ["dirA", "dirB"], "dir2": ["dirA", "dirB"]}
roundrobin

@BausTheBig - sorun değil. Cevabınızı düzenleyin ve ne istediğinize bir örnek ekleyin.
slm

OP'nin veri yapısı bir Python nesnesi gibi görünüyor. Python hakkında neredeyse hiç bilgim yok, bu yüzden yardım edemem ama sanırım bu tür yapıların inşa edilmesi daha kolay.
terdon

@terdon - Drav'a bıraktım, bu bize Hashes yapısına benziyordu.
slm

2

Ayrıca bazı JSON veya XML dosyasına linux klasörü / dosya ağacı çıktı için bir yol arıyordu. Neden bu basit terminal komutunu kullanmıyorsunuz:

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

Yani, sadece Linux treekomutu ve kendi parametrelerinizi yapılandırın. İşte -XXML çıktısı verir. Benim için sorun değil ve sanırım XML'yi JSON'a dönüştürmek için bir komut dosyası var.


1

Bu komutu deneyebilirsiniz:

tree -a -J -o *filename*

Dosya adını istediğiniz çıktı dosyası adıyla değiştirin.


JKomuta için böyle bir bayrak yok tree!!

Olumlu oy: on tree v1.7.0 Orada bir bayrak ... cheers
drl

1

Bu işi yapar. 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 = (', ', ' : '))

Ben alamadım
Pierre.Vriens

1
Böylece ağaç yapısı json'a dönüştürülür. Bu kodu bir dizinde çalıştırın ve soruda belirtildiği gibi json üretir.
Debodirno Chandra
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.