如何在Perl中从终端进行管道传输而不丢失颜色?

如何在Perl中从终端进行管道传输而不丢失颜色?,perl,bash,colors,terminal,pipe,Perl,Bash,Colors,Terminal,Pipe,我正在尝试编写一个perl脚本,它接受colorgcc(或将彩色文本打印到终端的任何其他脚本)的输出,添加/删除部分字符串,然后以与输入字符串相同的颜色打印结果 以下代码将在颜色生成脚本所生成的每一行前面打印“Hello World”。输出将全部为黑色,而输入为多色。如何修改此脚本以保留原始颜色 open(CMD, "color_producing_script |"); while(<CMD>) { print 'Hello World' . $_; } color\u

我正在尝试编写一个perl脚本,它接受colorgcc(或将彩色文本打印到终端的任何其他脚本)的输出,添加/删除部分字符串,然后以与输入字符串相同的颜色打印结果

以下代码将在颜色生成脚本所生成的每一行前面打印“Hello World”。输出将全部为黑色,而输入为多色。如何修改此脚本以保留原始颜色

open(CMD, "color_producing_script |");

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

color\u-producting\u脚本在管道中使用时是否会改变其行为?试一试

color_producing_script | cat
在命令行。它可能有一个选项,可以强制颜色输出,即使它是

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");
}
编辑:

您可以通过以下一种或多种方式修改脚本:

  • 注释测试并使其始终产生颜色输出
  • 添加支持读取设置是否着色的环境变量的功能
  • ~/.colorgccrc
    配置文件中添加支持颜色始终选项的功能
  • 添加支持“颜色始终”命令行选项的功能,您可以在将其余选项传递给编译器之前删除该选项
您还可以使用该脚本创建伪tty,如下所示:

unbuffer gcc file.c | cat
(其中,
cat
是备用收件人)


所有这些都基于从命令行使用
colorgcc
。在Perl脚本中应该有类似的操作。

许多生成彩色输出的程序会检测是否正在写入TTY,如果没有,则关闭颜色。这是因为当您只想捕获文本时,颜色代码很烦人,因此它们会自动尝试“做正确的事情”

从这样的程序捕获颜色输出的最简单方法是告诉它写入颜色,即使它没有连接到TTY。您必须阅读该程序的文档,以了解它是否具有该选项


另一个选项是使用管道而不是管道。在Perl中,您可以使用或来实现这一点,它们都是围绕低级模块的高级包装。

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");
}
除了在Perl中使用Pty而不是管道(正如cjm已经指出的那样),您还可以欺骗应用程序,使其认为其stdin是交互式的,而不是命令行上的管道

例如:

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

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

有关进一步的解决方案,请参见:

它确实会改变其行为<代码>颜色生成脚本| cat
生成所有黑色文本。有没有标准的bashshell方法来“强制”管道中的颜色?@LexFridman:没有,每个实用程序、程序或脚本都有自己的选项。这与贝壳无关。示例:
ls--color=always
grep--color=always
ack--color
。这是你写的剧本吗?它是使用这些实用程序中的一个还是其他一些?你能告诉我更多关于它做什么或者它是如何做的吗?大多数语言和操作系统都提供了一种方法来判断输出流是否正在写入终端设备。着色脚本可以在写入文件或管道时改变其行为。脚本是GCC C++编译器周围常用的Perl包装脚本,称为。我可以修改这个脚本,但我想避免这样做,因为它是在我的案例中使用Ubuntu打包系统分发的。它没有--color=始终标记。所以问题变成了,在将一个perl脚本传输到另一个perl脚本时,如何保持颜色?@LexFridman:请查看我编辑过的答案。在shell中除了使用例如
expect
创建伪tty之外,没有其他方法;脚本在通过管道时不会产生颜色。回答得好。没错。你准确地指出了问题所在。不确定colorgcc的版本控制系统是什么,但我认为最新版本是1.3.2。至少这是原始开发人员提供的,也是Ubuntu包存储库。正如我的第二次编辑所描述的,这个版本实际上在您提供的if语句中添加了一个键。另外,我应该注意到,您提出的
script-c
建议在保存颜色方面对我不起作用。因此,很多人都提出了这个解决方案,而且它似乎是一个很好的解决方案。谢谢但我不知道如何让它工作。Pty或您提到的包装器仍然相当复杂,不幸的是,文档非常薄弱。
# Linux
script -c "[executable string]" /dev/null

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