简体   繁体   English

如何从Perl终端管道而不会丢失颜色?

[英]How can I pipe from terminal in Perl without losing color?

I'm trying to write a perl script which takes the output of colorgcc (or any other script that prints colored text to terminal), adds/removes parts of the string, and then prints the result in the same color as the input string. 我正在尝试编写一个perl脚本,它接受colorgcc的输出(或任何其他将彩色文本打印到终端的脚本),添加/删除部分字符串,然后以与输入字符串相同的颜色打印结果。

The following code will print "Hello World" in front of each line produced by the color_producing_script . 以下代码将在color_producing_script生成的每一行前面打印“Hello World”。 The output will be all black, while the input is multicolored. 输出将全部为黑色,而输入为多色。 How can I modified this script to conserve the original colors? 如何修改此脚本以保留原始颜色?

open(CMD, "color_producing_script |");

while(<CMD>) {
    print 'Hello World' . $_;
}

I'm using bash terminal. 我正在使用bash终端。

Edit 编辑

Per the excellent first comment, this is not a Perl issue per se. 根据优秀的第一条评论,这本身并不是Perl问题。 Just running color_producing_script | cat 刚刚运行color_producing_script | cat color_producing_script | cat strips the color off. color_producing_script | cat脱掉了颜色。 So the question can be rephrased to "How do you force color through the pipe?" 因此,问题可以改为“你如何通过管道强制颜色?”

Edit 2 编辑2

It looks like the latest version of gcc (1.3.2) includes the CGCC_FORCE_COLOR environment variable in the if clause, and if it's defined, colorgcc forces color: 看起来最新版本的gcc(1.3.2)在if子句中包含了CGCC_FORCE_COLOR环境变量,如果已定义,colorgcc会强制颜色:

export CGCC_FORCE_COLOR=true

Does color_producing_script change its behavior when it's used in a pipe? color_producing_script在管道中使用时是否color_producing_script改变其行为? Try 尝试

color_producing_script | cat

at the command line. 在命令行。 It may have an option to force color output even when it is. 它可能有一个强制颜色输出的选项,即使它是。

The Perl script, colorgcc , is specifically checking to see if output is to a non-tty and skipping the colorization if that's the case. Perl脚本colorgcc专门检查输出是否为非tty,如果是这种情况则跳过着色。

# Get the terminal type. 
$terminal = $ENV{"TERM"} || "dumb";

# If it's in the list of terminal types not to color, or if
# we're writing to something that's not a tty, don't do color.
if (! -t STDOUT || $nocolor{$terminal})
{
   exec $compiler, @ARGV
      or die("Couldn't exec");
}

Edit: 编辑:

You could modify the script in one or more of the following ways: 您可以通过以下一种或多种方式修改脚本:

  • comment out the test and make it always produce color output 注释掉测试并使其始终产生颜色输出
  • add functionality to support reading an environment variable that sets whether to colorize 添加功能以支持读取设置是否着色的环境变量
  • add functionality to support a color-always option in the ~/.colorgccrc configuration file 添加功能以支持~/.colorgccrc配置文件中的color-always选项
  • add functionality to support a color-always command line option that you strip before passing the rest of the options to the compiler 添加功能以支持在将其余选项传递给编译器之前删除的color-always命令行选项

You could also use the expect script unbuffer to create a pseudo-tty like this: 您还可以使用expect脚本unbuffer来创建一个伪tty,如下所示:

unbuffer gcc file.c | cat

(where cat is a standin recipient). (其中cat是替代收件人)。

All of this is based on using colorgcc from the command line. 所有这些都基于从命令行使用colorgcc There should be analogs for doing similar things within a Perl script. 应该有类比在Perl脚本中做类似的事情。

Many programs that generate colored output detect if they're writing to a TTY, and switch off colors if they aren't. 许多生成彩色输出的程序会检测它们是否正在写入TTY,如果不是则会关闭颜色。 This is because color codes are annoying when you only want to capture the text, so they try to "do the right thing" automatically. 这是因为当您只想捕获文本时,颜色代码很烦人,因此他们会尝试自动“做正确的事情”。

The simplest way to capture color output from a program like that is to tell it to write color even though it's not connected to a TTY. 从类似程序中捕获颜色输出的最简单方法是告诉它写入颜色,即使它没有连接到TTY。 You'll have to read the program's documentation to find out if it has that option. 您必须阅读该程序的文档,以确定它是否具有该选项。

The other option is to use a Pty instead of a pipe. 另一种选择是使用Pty而不是管道。 In Perl, you can do this with IO::Pty::HalfDuplex or IO::Pty::Easy , both of which are higher-level wrappers around the low-level module IO::Pty . 在Perl中,您可以使用IO :: Pty :: HalfDuplexIO :: Pty :: Easy执行此操作 ,这两者都是低级模块IO :: Pty的高级包装器。

The source code of ColorGCC is quite clear about this topic! ColorGCC的源代码非常清楚这个主题!

#! /usr/bin/perl -w
# ...
# from: colorgcc-4.1.2/colorgcc-4.1.2
# downloaded from: http://www.console-colors.de/index.php?n=ConsColors.Downloads
#
# Note:
#
# colorgcc will only emit color codes if:
# 
#    (1) Its STDOUT is a tty and
#    (2) the value of $TERM is not listed in the "nocolor" option.
#
# If colorgcc colorizes the output, the compiler's STDERR will be
# combined with STDOUT. Otherwise, colorgcc just passes the output from
# the compiler through without modification.
# .....
# If it's in the list of terminal types not to color, or if
# we're writing to something that's not a tty, don't do color.
if (! -t STDOUT || $nocolor{$terminal})
{
   exec $compiler, @ARGV
      or die("Couldn't exec");
}

In addition to use a Pty instead of a pipe in Perl (as already pointed out by cjm) you can trick an application into thinking its stdin is interactive, not a pipe on the command line as well. 除了在Perl中使用Pty而不是管道(正如cjm已经指出的那样),你可以欺骗应用程序认为它的stdin是交互式的,而不是命令行上的管道。

For example: 例如:

# Linux
script -c "[executable string]" /dev/null

# FreeBSD, Mac OS X
script -q /dev/null "[executable string]"

For further solutions see: bash: force exec'd process to have unbuffered stdout 有关进一步的解决方案,请参阅: bash:强制exec'd进程具有无缓冲的stdout

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM