GNU/Linux >> Tutoriales Linux >  >> Linux

¿Convertir la salida del comando Tree a formato Json?

¿Hay alguna manera conveniente de convertir la salida del comando *nix "árbol" al formato JSON?

Editar:
Creo que no describí mi problema lo suficientemente bien. Mi objetivo es convertir algo como:

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

en:

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

Respuesta aceptada:

Intento 1

Una solución que usa solo perl, devolviendo una estructura simple de hash de hash. Antes del
OP aclaraba el formato de datos de 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 El módulo funciona de manera similar a find de Unix. dominio. El JSON El módulo toma variables de Perl y las convierte en JSON.

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

Iterará hacia abajo la estructura del archivo desde el directorio de trabajo actual llamando a la subrutina process_dir para cada archivo/directorio bajo “.”, y el no_chdir decirle a perl que no emita un chdir() para cada directorio que encuentra.

process_dir devuelve si el presente archivo examinado no es un directorio:

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

Luego tomamos una referencia del hash existente %$dirs en $ref , divida la ruta del archivo alrededor de / y bucle con for agregando una nueva clave hash para cada ruta.

Haciendo una estructura de directorios como lo hizo slm:

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

La salida es:

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

Intento 2

Bien, ahora con una estructura de datos diferente...

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

Y luego ejecutar el script en la estructura de directorios propuesta...

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

Encontré esto bastante complicado de hacer bien (especialmente dada la lógica "hash si subdirectorios, matriz si no, OH A MENOS que sea de nivel superior, entonces solo hashes de todos modos"). Así que
me sorprendería si esto fuera algo que pudieras hacer con sed / awk … pero entonces
Stephane no ha mirado esto todavía, apuesto 🙂

Relacionado:¿Cómo funciona el comando de salida en una terminal Unix?
Linux
  1. Bash Convertir \xc3\x89 a É?

  2. Ejemplos de comandos de tiempo de Linux

  3. Visualización de la salida completa del comando PS

  4. Número de dispositivo en la salida del comando stat

  5. Convertir una salida a cadena

Ccat – Colorear la salida del comando Cat

Mostrar la salida del comando Ping en formato gráfico usando Gping

Comando iftop en Linux

Comando de árbol en Linux

Comando lsblk en Linux

Ejemplos de comandos echo de Linux