GNU/Linux >> Linux の 問題 >  >> Linux

ツリーコマンドの出力をJson形式に変換しますか?

* nixコマンド「tree」の出力をJSON形式に変換する便利な方法はありますか?

編集:
問題を十分に説明できなかったと思います。私の目標は次のようなものを変換することです:

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

に:

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

承認された回答:

試行1

perlだけを使用して、ハッシュ構造の単純なハッシュを返すソリューション。
OPが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 モジュールは、UNIXのfindと同じように機能します 指図。 JSON モジュールはperl変数を受け取り、それらをJSONに変換します。

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

サブルーチンprocess_dirを呼び出して、現在の作業ディレクトリからファイル構造を繰り返し処理します 「。」の下の各ファイル/ディレクトリ、およびno_chdir chdir()を発行しないようにperlに指示します 見つかったディレクトリごとに。

process_dir 現在調べているファイルがディレクトリでない場合に返されます:

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

次に、既存のハッシュ%$dirsの参照を取得します $refに 、ファイルパスを/で分割します forでループします パスごとに新しいハッシュキーを追加します。

slmのようなディレクトリ構造の作成:

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

出力は次のとおりです。

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

試行2

さて、別のデータ構造で…

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

そして、提案されたディレクトリ構造でスクリプトを実行します…

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

私はこれを正しく理解するのが非常に難しいことに気づきました(特に「サブディレクトリの場合はハッシュ、そうでない場合は配列、トップレベルでない限り、とにかくハッシュする」ロジックが与えられます)。だから
これがsedでできることだとしたら驚きます / awk …しかし、
ステファンはまだこれを見ていません、私は賭けます🙂

関連:Unix端末でexitコマンドはどのように機能しますか?
Linux
  1. Unix のトップ コマンド出力を読み取り可能な形式でファイルにキャプチャする方法

  2. Linux 時間コマンドの例

  3. Linux での pinky コマンドの例

  1. PS コマンドの完全な出力の表示

  2. stat コマンド出力のデバイス番号

  3. bash `ls` 出力を json 配列に変換します

  1. コマンド出力またはファイルの内容を列形式で表示する

  2. 出力を文字列に変換する

  3. docker でのコマンド出力のリダイレクト