【问题标题】:Coloring Perl output on windows command prompt在 Windows 命令提示符下着色 Perl 输出
【发布时间】:2020-02-26 23:21:23
【问题描述】:

这个问题与以下问题有关: How do I color output text from Perl script on Windows?

但是更具体一点。在某种程度上,我已经获得了跨平台着色工作:

use Term::ANSIColor;
use Win32::Console;

if (!(-f STDOUT)) {
    if ($^O =~ /win/) {
        our $FG_BLUE;
        our $FG_YELLOW;
        our $FG_RED;
        our $BG_GREEN;
        my $CONSOLE = Win32::Console->new(STD_OUTPUT_HANDLE);
        my $attr = $CONSOLE->Attr(); # Get current console colors
        $blue   = sub {$CONSOLE->Attr($FG_BLUE);return};
        $reset  = sub {$CONSOLE->Attr($attr);return};
        $yellow = sub {$CONSOLE->Attr($FG_YELLOW);return};
        $red    = sub {$CONSOLE->Attr($FG_RED);return};
    } else {
        $blue   = sub {return color('bold blue')};
        $reset  = sub {return color('reset')};
        $yellow = sub {return color('yellow')};
        $red    = sub {return color('red')};
    }
}

但是当从字符串内部调用函数时,终端颜色不会立即改变,因此:

    print "${\$blue->()} this is blue\n";
    print "${\$blue->()}This is... not blue${\$reset->()}\n";
    print "this is Blue ${\$blue->()}\n";
    print "this is reset${\$reset->()}\n";

我想知道是否可以执行以下操作:

    my $print_help = <<PRINT_HELP;
    Usage:  $toolname [-Options] [-fields name1,[name2],...]
    ${\$red->()} toolname version VERSION ${\$reset->()} 
    ${\$blue->()} options: ${\$reset->()}

    PRINT_HELP

    print $print_help;

打印没有颜色。我试过设置 $| = 1 没有运气。

我没有在相关系统上安装 Win32::Console::ANSI 的选项,因此我无法使任何使用该模块的解决方案工作。

【问题讨论】:

  • 如果你将heredoc结束字符串放在双引号中,我相信你会得到现在没有发生的变量扩展。即&lt;&lt;"PRINT_HELP" 在功能上与您现在所拥有的不同。
  • 不幸的是,在这种情况下,引号中的 heredoc 似乎不会影响功能。在heredoc中已经发生了变量扩展,只是子程序在打印出任何东西之前都在执行。由于颜色更改是在函数调用时进行的,而不是打印出特殊字符,因此所有更改都是在打印任何文本之前进行的。

标签: windows perl cmd colors windows-console


【解决方案1】:

这种技巧可能符合您的需要。

#!/usr/bin/perl

use warnings;
use strict;

my $alice = sub  { return 'ALICE'; };

my $bob = sub { return 'BOB'; };

my $test = <<'ENDTEST';
lineone
line2 ${\$alice->()} endline
line3 startline ${\$bob->()}
linefour
linefive
ENDTEST

# Add spaces around newline, split on horizontal whitespace
$test =~ s/\n/ \n /g;
my @testtokens = split /\h/, $test;

# Print '%s ' for each of the testtokens
# Print newlines, evaluate all testtokens beginning with '$', otherwise print
map { /\n/ ? print : printf '%s ', /^\$/ ? eval $_ : $_} @testtokens;

获取 ENDTEST heredoc 并在最后一行打印:

$ heretest.pl
lineone 
line2 ALICE endline 
line3 startline BOB 
linefour 
linefive 

也许会按顺序评估事物。

【讨论】:

  • 这个解决方案确实有一些陷阱,IE:如果下一行以变量开头,则需要在行尾放置空格,并且变量后需要空格,但做类似的事情,除了在花括号上拆分可能会更好。感谢您的解决方案!
【解决方案2】:

在您开始打印之前,您正在调用redresetbluereset。您可以使用模板。这是一个强大的实现:

use FindBin qw( $RealBin );
use lib "$RealBin/lib";

use My::Console qw( );

my $console = My::Console->new;

my $print_help = <<'__END_OF_HELP__';
Usage:  $toolname [-Options] [-fields name1,[name2],...]
{{red}}toolname version VERSION{{reset}}
{{blue}}options:{{reset}}

__END_OF_HELP__

$console->print_with_color($print_help);

lib/My/Console.pm:

package My::Console;

use strict;
use warnings;

my $console;
BEGIN {
   if (!-t STDOUT) {
      require My::Console::Dumb;
      $console = My::Console::Dumb::;
   }
   elsif ($^O eq 'Win32') {
      require My::Console::Win32;
      $console = My::Console::Win32::;
   }
   else {
      require My::Console::ANSI;
      $console = My::Console::ANSI::;
   }
}

sub new { $console }

1;

lib/My/Console/Base.pm:

package My::Console::Base;

use strict;
use warnings;

use Carp qw( croak );

my %allowed_cmds = map { $_ => 1 } qw( red blue reset );

sub red   { }
sub blue  { }
sub reset { }

sub print { print(STDOUT @_); }

sub print_with_color {
   my $self = shift;

   for (@_) {
      /\G ( (?: [^{] | \{(?!\{) )+ ) /xgc
         and $self->print($1);

      /\G \z /xgc
         and next;

      /\G \{\{ /xgc;

      /\G ( (?: [^}] | \}(?!\}) )* ) \}\} /xgc
         or croak("Bad template");

      my $cmd = $1;
      if ($cmd eq "") {
         # An escape mechanism. Use "{{}}" to output "{{".
         $self->print("{{");
         redo;
      }

      $allowed_cmds{$cmd}
         or croak("Unrecognized command \"$cmd\"");

      $self->$cmd();
      redo;
   }
}

1;

lib/My/Console/Win32.pm:

package My::Console::Win32;

use strict;
use warnings;

use My::Console::Base qw( );
use Win32::Console;

our @ISA = My::Console::Base::;

my $CONSOLE = Win32::Console->new(STD_OUTPUT_HANDLE);
my $initial_console_attr = $CONSOLE->Attr();

sub red   { STDOUT->flush; $CONSOLE->Attr($FG_RED); }
sub blue  { STDOUT->flush; $CONSOLE->Attr($FG_BLUE); }
sub reset { STDOUT->flush; $CONSOLE->Attr($initial_console_attr); }

1;

lib/My/Console/ANSI.pm:

package My::Console::ANSI;

use strict;
use warnings;

use My::Console::Base qw( );
use Term::ANSIColor   qw( );

our @ISA = My::Console::Base::;

sub red   { print(Term::ANSIColor::red()); }
sub blue  { print(Term::ANSIColor::blue()); }
sub reset { print(Term::ANSIColor::reset()); }

1;

lib/My/Console/Dumb.pm:

package My::Console::Dumb;

use strict;
use warnings;

use My::Console::Base qw( );

our @ISA = My::Console::Base::;

1;

【讨论】:

  • 出于好奇,:: 末尾的our @ISA = My::Console::Base:: 的目的是什么?为什么不只是our @ISA = My::Console::Base
  • @HåkonHægland 这不是有效的 Perl(除非严格关闭)
  • 嗯.. 根据perlbobj 它应该是有效的? perlmod 还提到了符号表,这些符号表存储在与包同名的哈希中,并附加了两个冒号。但它没有提到这些哈希将用于@ISA。此外,我在谷歌上找不到任何以这种方式使用 @ISA 的示例......我错过了什么吗?
  • @Håkon Hægland,我不明白你为什么认为其中任何一个是相关的,或者为什么你认为包名称是有效的表达,但 they're not。就像my $x = foo;在严格下一般是错误的,我的$x = Foo::Bar;也是。 (My::Console::Base 如果命名为 sub 则有效,但这会产生错误的结果,因为我们正在尝试生成字符串 My::Console::Base。)
  • @Håkon Hægland,我使用的方式更短,如果您提供不存在的包,则会发出警告。它在其他方面是等效的(返回字符串My::Console::Base)。
【解决方案3】:

我的控制台不支持颜色,但我可以看到支持颜色的控制台上的 ESCAPE 代码应该可以工作。我想知道它是否适合你?

#!/usr/bin/perl

use Term::ANSIColor;
use Win32::Console;

if (!(-f STDOUT)) {
    if ($^O =~ /win/) {
        our $FG_BLUE;
        our $FG_YELLOW;
        our $FG_RED;
        our $BG_GREEN;
        my $CONSOLE = Win32::Console->new(STD_OUTPUT_HANDLE);
        my $attr = $CONSOLE->Attr(); # Get current console colors
        $blue   = sub {$CONSOLE->Attr($FG_BLUE);return};
        $reset  = sub {$CONSOLE->Attr($attr);return};
        $yellow = sub {$CONSOLE->Attr($FG_YELLOW);return};
        $red    = sub {$CONSOLE->Attr($FG_RED);return};
    } else {
        $blue   = sub {return color('bold blue')};
        $reset  = sub {return color('reset')};
        $yellow = sub {return color('yellow')};
        $red    = sub {return color('red')};
    }
}

help();

sub help {
    print 
"
    Usage:  $toolname [-Options] [-fields name1,[name2],...]
    ${\$red->()} toolname version VERSION ${\$reset->()} 
    ${\$blue->()} options: ${\$reset->()}

";
}

问题:为什么不使用POD

【讨论】:

  • 据我所知,POD 可能适用于此,但我以前没有使用过它。我去看看,谢谢~
猜你喜欢
  • 2014-04-16
  • 2013-06-21
  • 1970-01-01
  • 1970-01-01
  • 2011-10-28
  • 1970-01-01
  • 1970-01-01
  • 2014-11-22
相关资源
最近更新 更多