GNU/Linux >> Belajar Linux >  >> Linux

Ubah Output Perintah Pohon Ke Format Json?

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

Sunting:
Saya rasa saya tidak cukup menggambarkan masalah saya. Tujuan saya adalah mengonversi sesuatu seperti:

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

menjadi:

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

Jawaban yang Diterima:

Percobaan 1

Solusi hanya menggunakan Perl, mengembalikan hash sederhana dari struktur hash. 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::Find modul bekerja dengan cara yang mirip dengan unix find memerintah. JSON module mengambil variabel Perl dan mengubahnya menjadi JSON.

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

Akan mengulangi struktur file dari direktori kerja saat ini dengan memanggil subrutin process_dir untuk setiap file/direktori di bawah “.”, dan no_chdir beri tahu Perl untuk tidak mengeluarkan chdir() untuk setiap direktori yang ditemukannya.

process_dir kembali jika file yang diperiksa saat ini bukan direktori:

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

Kami kemudian mengambil referensi dari hash yang ada %$dirs ke $ref , bagi jalur file di sekitar / dan loop dengan for menambahkan kunci hash baru untuk setiap jalur.

Membuat struktur direktori seperti yang dilakukan slm:

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 diperbaiki (terutama mengingat "hash jika sub direktori, array jika tidak, OH KECUALI tingkat atas, maka hanya hash") logika). Jadi
Saya akan terkejut jika ini adalah sesuatu yang dapat Anda lakukan dengan sed / awk … tapi kemudian
Stephane belum melihat ini, saya yakin

Terkait:Bagaimana cara kerja perintah keluar pada terminal Unix?
Linux
  1. Cara Menangkap Output Perintah Teratas Unix ke File dalam Format yang Dapat Dibaca

  2. Contoh Perintah Waktu Linux

  3. Contoh Perintah pinky di Linux

  1. Melihat output penuh dari perintah PS

  2. Nomor perangkat dalam keluaran perintah stat

  3. konversi keluaran bash `ls` ke array json

  1. Ubah keluaran ls menjadi csv

  2. Ubah output menjadi string

  3. Mengarahkan output perintah di buruh pelabuhan