显示目录树输出,如树命令

时间:2012-05-15 18:28:47

标签: perl tree directory traversal tree-traversal

我仍然使用了很棒的Path::Class模块来遍历目录。我写了一段代码,但我对显示输出不满意。我的目录树输出不像tree命令的输出那样简洁明了。 : - (

到目前为止我的代码:

use strict;
use warnings;
use Path::Class;

my $dir = Path::Class::Dir->new('D:\dev\pl\testdir');

my $max_depth = $dir->traverse(sub {
  my ($child, $cont, $depth) = @_;
  return max($cont->($depth + 1), $depth);
}, 0);
sub max { my $max = 0; for (@_) { $max = $_ if $_ > $max } $max };

# Print header
printf "%-43s|%s\n", " Name", " mtime";
printf "%-43s|%s\n", '-' x 43, '-' x 11;

$dir->traverse(sub {
  my ($child, $cont, $indent) = @_;
  my $child_basename = $child->basename;
  my $child_stat     = $child->stat();
  my $child_mtime    = $child_stat->[9];
  $indent //= 0;
  my $width = 40 - 3 * ($indent - 1);

  #print "DEBUG: Scanning $child\n";

  if ($indent == 0) {
    print "ROOT: ", $child, "\n";
  }
  else {
    if ($child->is_dir) {
        print '   ' x ($indent - 1), '+- ';
        printf "%-${width}s| %d", $child_basename . '/', $child_mtime;
        print "\n";
    } else {
        print '   ' x ($indent - 1), '|- ';
        printf "%-${width}s| %d", $child_basename, $child_mtime;
        print "\n";
    }
  }

  $cont->($indent + 1);
});

我的错误的输出是:

Name                                       | mtime
-------------------------------------------|-----------
ROOT: D:\dev\pl\testdir
+- Path-Class-0.25/                        | 1337013211
   |- Build.PL                             | 1329360988
   |- Changes                              | 1329360988
   |- dist.ini                             | 1329360988
   |- INSTALL                              | 1329360988
   +- lib/                                 | 1337013211
      +- Path/                             | 1337013211
         +- Class/                         | 1337013211
            |- Dir.pm                      | 1329360988
            |- Entity.pm                   | 1329360988
            |- File.pm                     | 1329360988
         |- Class.pm                       | 1329360988
   |- LICENSE                              | 1329360988
   |- Makefile.PL                          | 1329360988
   |- MANIFEST                             | 1329360988
   |- META.yml                             | 1329360988
   |- README                               | 1329360988
   |- SIGNATURE                            | 1329360988
   +- t/                                   | 1337013211
      |- 01-basic.t                        | 1329360988
      |- 02-foreign.t                      | 1329360988
      |- 03-filesystem.t                   | 1329360988
      |- 04-subclass.t                     | 1329360988
      |- 05-traverse.t                     | 1329360988
      |- author-critic.t                   | 1329360988

正确输出(也更好看)应为:

Name                                       | mtime
-------------------------------------------|-----------
ROOT: D:\dev\pl\testdir
+- Path-Class-0.25/                        | 1337013211
   |- Build.PL                             | 1329360988
   |- Changes                              | 1329360988
   |- dist.ini                             | 1329360988
   |- INSTALL                              | 1329360988
   +- lib/                                 | 1337013211
   |  +- Path/                             | 1337013211
   |     +- Class/                         | 1337013211
   |     |  |- Dir.pm                      | 1329360988
   |     |  |- Entity.pm                   | 1329360988
   |     |  |- File.pm                     | 1329360988
   |     \- Class.pm                       | 1329360988
   |- LICENSE                              | 1329360988
   |- Makefile.PL                          | 1329360988
   |- MANIFEST                             | 1329360988
   |- META.yml                             | 1329360988
   |- README                               | 1329360988
   |- SIGNATURE                            | 1329360988
   \- t/                                   | 1337013211
      |- 01-basic.t                        | 1329360988
      |- 02-foreign.t                      | 1329360988
      |- 03-filesystem.t                   | 1329360988
      |- 04-subclass.t                     | 1329360988
      |- 05-traverse.t                     | 1329360988
      \- author-critic.t                   | 1329360988

您能否改进或更正我的代码?

非常感谢您的帮助!

的问候,
斯科特

2 个答案:

答案 0 :(得分:3)

下面的代码不是花哨的解决方案,但它适用于您希望>>

#!/usr/bin/perl

use strict;
use warnings;
use Path::Class;

my $dir = Path::Class::Dir->new('D:\dev\pl\testdir');

my $max_depth = $dir->traverse(sub {
  my ($child, $cont, $depth) = @_;
  return max($cont->($depth + 1), $depth);
}, 0);

sub max { my $max = 0; for (@_) { $max = $_ if $_ > $max } $max };

my @output = ( sprintf("%-43s|%s", " Name", " mtime"),
               sprintf("%-43s|%s", '-' x 43, '-' x 11) );

my @tree = (0, 0);
my $last_indent = 0;

$dir->traverse( sub {
  my ($child, $cont, $indent) = @_;
  my $child_basename = $child->basename;
  my $child_stat     = $child->stat();
  my $child_mtime    = $child_stat->[9];

  $indent = 1 if (!defined $indent);
  my $width = 40 - 3 * ($indent - 1);

  if ($last_indent != $indent) {
    if ($last_indent > ($indent + 1)) {
      for my $level (($indent + 1)..($last_indent - 1)) {
        $output[$#output - $_] = 
          substr($output[$#output - $_], 0, 3 * ($level - 1)) . ' ' .
          substr($output[$#output - $_], 3 * ($level - 1) + 1, 65535) 
            for (0..$tree[$level] - 1);
      }
      delete $tree[$_] for $indent..$last_indent;
    }
    $tree[$indent] = 0;
    $last_indent = $indent;
  }

  if ($child->is_dir) {
    push @output, sprintf("%s+- %-${width}s| %d",
      ('|  ' x ($indent - 1)), $child_basename . '/', $child_mtime);
    $tree[$indent] = 0;
  }
  else {
    push @output, sprintf("%s%s- %-${width}s| %d", ('|  ' x ($indent - 1)),
      ($child eq ($child->dir->children)[-1] ? '\\' : '|' ),
      $child_basename, $child_mtime);
    $tree[$indent]++;
  }
  $tree[$_]++ for (1..$indent - 1);

  $cont->($indent + 1);
});

for my $level (1..$last_indent - 1) {
  $output[$#output - $_] = 
    substr($output[$#output - $_], 0, 3 * ($level - 1)) . ' ' .
    substr($output[$#output - $_], 3 * ($level - 1) + 1, 65535)
      for (0..$tree[$level] - 1);
}

print "$_\n" for @output;

答案 1 :(得分:0)

if ($child->is_dir) {
    printf "%s+- %-${width}s| %d\n",
        ('|  ' x ($indent - 1)),
        $child_basename . '/',
        $child_mtime;
} else {
    printf "%s%s- %-${width}s| %d\n",
        ('|  ' x ($indent - 1)),
        ($child eq ($child->dir->children)[-1] ? '\\' : '|' ),
        $child_basename,
        $child_mtime;
}

此外,ASCII线会导致眼癌。请使用正确的box drawing characters