GNU/Linux >> Tutoriels Linux >  >> Linux

Convertir la sortie de la commande Tree au format Json ?

Existe-t-il un moyen pratique de convertir la sortie de la commande *nix "tree" au format JSON ?

Modifier :
Je pense que je n'ai pas assez bien décrit mon problème. Mon objectif est de convertir quelque chose comme :

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

dans :

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

Réponse acceptée :

Tentative 1

Une solution utilisant uniquement Perl, renvoyant une simple structure de hachage de hachages. Avant le
OP a clarifié le format de données 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 module fonctionne de manière similaire au module unix find commande. Le JSON module prend des variables perl et les convertit en JSON.

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

Itérera la structure du fichier à partir du répertoire de travail actuel en appelant la sous-routine process_dir pour chaque fichier/répertoire sous ".", et le no_chdir dire à perl de ne pas émettre de chdir() pour chaque répertoire qu'il trouve.

process_dir retourne si le fichier actuellement examiné n'est pas un répertoire :

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

Nous récupérons ensuite une référence du hachage existant %$dirs dans $ref , divisez le chemin du fichier autour de / et boucle avec for en ajoutant une nouvelle clé de hachage pour chaque chemin.

Faire une structure de répertoire comme slm :

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

La sortie est :

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

Essai 2

Ok maintenant avec une structure de données différente…

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

Et puis exécuter le script sur la structure de répertoires proposée…

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

J'ai trouvé cela sacrément difficile à faire correctement (en particulier compte tenu de la logique "hash if sub directorys, array if not, OH UNLESS top level, then just hashes whenaway"). Donc
je serais surpris si c'était quelque chose que vous pouviez faire avec sed / awk … mais alors
Stéphane n'a pas encore regardé ça je parie 🙂

En relation :Comment fonctionne la commande exit sur un terminal Unix ?
Linux
  1. Comment capturer la sortie de la commande supérieure Unix dans un fichier au format lisible

  2. Exemples de commande de temps Linux

  3. 12 Exemples d'options de format de sortie de commande de temps UNIX/Linux

  4. Exemples de commandes pinky sous Linux

  5. Affichage de la sortie complète de la commande PS

Ccat - Coloriser la sortie de la commande Cat

Afficher la sortie de la commande Ping au format graphique à l'aide de Gping

Commande iftop sous Linux

Commande d'arborescence sous Linux

Commande lsblk sous Linux

Exemples de commandes echo Linux