使用Curses显示实时数据

有时,终端界面是获取答案的最简单方式,当它是时,我喜欢使用Curses来使体验愉快。在这篇文章中,我将重新编写一个我多次编写的Curses程序,主要是因为我在创建它上一次时忘记了放在哪里(这一次我发现我已经将它发布到了Perlmonks)。

每次我重新发明它时,我都会以不同于以前的方式编写它,现在我想要更新它以适应Perl的新特性,主要是它的子程序签名

有一天,我有一个小任务要修剪目录树,并想查看其中的最大文件。我了解du,并且知道它可以显示文件及其大小列表

$ du -a
16  ./apache2/extra
16  ./apache2/original/extra
32  ./apache2/original
0   ./apache2/other
16  ./apache2/users
192 ./apache2
0   ./asl
104 ./certificates
...
12904

问题是该命令的深度优先遍历。一旦我有了输出,我可以玩各种技巧来排序它,但对于一个大型目录,我希望看到结果实时到来。Perl作为Unix粘合语言(瑞士军刀等),非常适合这项工作。我可以读取du的实时输出,并以我想要的方式显示它。

第一部分很简单。我可以打开一个管道到外部命令(参见我之前的文章愚蠢的open技巧)。这次,我使用的是三参数管道-open,而不是我之前使用的两参数形式。

open my $pipe, '-|', 'du -a';

之后,我需要显示数据。我的概念是屏幕上的列表将更新为迄今为止最大的文件。我将每行输出分割成其大小和文件名,并将它们添加到列表中。我已经创建了一个类来处理这个问题,包括决定哪些文件足够大以显示的部分

my $files = Local::files->new;

while( <$pipe> ) {
  chomp;
  my( $size, $file ) = split /\s+/, $_, 2;
  next if -d $file;
  next if $file eq ".";
  $files->add( $size, "$file" );
}

接下来,我更新了Perl 5.12的包NAME BLOCK语法,它允许我在块外声明package

package Local::files {
  ...
}

其余的是列表操作和Curses内容。我不会详细介绍列表代码。基本上,如果下一个项目的大小大于列表中最后一个元素的大小,则新的较大元素将替换现有的元素。之后,我将列表排序。

Curses的设置很简单。它已经知道屏幕大小。

sub init ($self) {
  initscr;
  curs_set(0); # hide cursor
  $win = Curses->new;

  for( my $i = MAX; $i >= 0; $i-- ) {
    $self->size_at( $i, undef );
    $self->name_at( $i, '' );
  }
}

我需要记住在结束时调用endwin来撤销Curses所做的所有魔法,所以我将DESTROY放在通过初始设置的后面。

sub DESTROY { endwin; }

一旦我有了一个排序的列表,我必须将其绘制到屏幕上。这涉及到两个方面。我需要擦除已经存在的内容,这样较短的文件名就不会留下可能被较长的文件名替换的部分。《code>addstr在屏幕上放置文本(左上角是(1,1))。在调用refresh之前,不会有任何新的文本显示出来。

sub draw ($self) {
  for( my $i = 0; $i < MAX; $i++ ) {
    next if $self->size_at( $i ) == 0 or $self->name_at( $i ) eq '';
    $win->addstr( $i,  1, " " x $Curses::COLS );
    $win->addstr( $i,  1, sprintf( "%8d", $self->[$i][SIZE] || '' )  );
    $win->addstr( $i, 10, $self->name_at( $i ) );
    $win->refresh;
  }
}

现在我有一个小脚本,它会在实时排序最大文件列表时向屏幕输出一些花哨的内容。这里是一个针对我的MiniCPAN目录的运行示例

按照我的编写方式,我必须从我想检查的目录中运行它。这样我可以避免各种关于taint检查和奇怪的目录名的麻烦。你可以很容易地使其在其他情况下工作。你甚至可以修改这个程序来列出其他内容。列表管理的内容已经存在,并且它并不真正关心特定的问题。完整的代码在GitHub上作为briandfoy/du-curses


这篇文章最初发布在PerlTricks.com上。

标签

brian d foy

brian d foy 是一名 Perl 训练师和作家,也是 Perl.com 的高级编辑。他是《精通 Perl》、《Mojolicious Web Clients》、《Learning Perl Exercises》的作者,以及《Programming Perl》、《Learning Perl》、《Intermediate Perl》和《Effective Perl Programming》的合著者。

浏览他们的文章

反馈

这篇文章有什么问题吗?请在 GitHub 上打开一个 issue 或 pull request 来帮助我们。