GNU/Linux >> Linux Esercitazione >  >> Linux

Converti l'output del comando ad albero in formato Json?

Esiste un modo conveniente per convertire l'output del comando *nix "tree" in formato JSON?

Modifica:
Penso di non aver descritto abbastanza bene il mio problema. Il mio obiettivo è convertire qualcosa come:

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

in:

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

Risposta accettata:

Tentativo 1

Una soluzione che utilizza solo perl, restituendo una semplice struttura hash di hash. Prima dell'
OP ha chiarito il formato dei dati di 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 il modulo funziona in modo simile a unix find comando. Il JSON il modulo prende le variabili perl e le converte in JSON.

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

Itererà la struttura del file dalla directory di lavoro attuale chiamando la subroutine process_dir per ogni file/directory in "." e no_chdir di' a perl di non emettere un chdir() per ogni directory che trova.

process_dir restituisce se il file attualmente esaminato non è una directory:

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

Quindi prendiamo un riferimento dell'hash esistente %$dirs in $ref , suddividi il percorso del file attorno a / e continua con for aggiungendo una nuova chiave hash per ogni percorso.

Creare una struttura di directory come ha fatto slm:

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

L'output è:

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

Tentativo 2

Va bene ora con una struttura dati diversa...

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

E quindi eseguire lo script sulla struttura di directory proposta...

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

Ho trovato questo dannatamente difficile da ottenere (soprattutto data la logica "hash se sottodirectory, array se no, OH A MENO di livello superiore, quindi solo hash comunque"). Quindi
sarei sorpreso se questo fosse qualcosa che potresti fare con sed / awk … ma poi
Stephane non ha ancora guardato questo scommetto 🙂

Correlati:come funziona il comando exit su un terminale Unix?
Linux
  1. 12 Esempi di opzioni per il formato di output del comando ora UNIX / Linux

  2. tee Esempi di comandi in Linux

  3. Visualizzazione dell'output completo del comando PS

  4. Numero del dispositivo nell'output del comando stat

  5. convertire l'output di bash `ls` in un array json

Ccat:colora l'output del comando Cat

Visualizza l'output del comando Ping in formato grafico utilizzando Gping

comando iftop in Linux

Comando ad albero in Linux

Comando lsblk in Linux

Esempi di comandi echo Linux