可以通过 shell 重定向捕获带颜色的输出吗?

108

我使用各种bash命令,例如漂亮的差异显示、构建脚本等,这些命令会产生大量的彩色输出。

当我将这些输出重定向到文件中,并在之后使用catless命令查看文件时,颜色就没了——可能是因为重定向操作去除了终端颜色代码。

有没有一种方法可以捕获带有颜色的输出呢?


1
笑死了,这个重复通知:“如何欺骗应用程序认为它的标准输出是终端而不是管道”,似乎与“是否可以通过shell重定向捕获带颜色的输出”是同一个问题。 - Philipp
7个回答

77

使用script命令是捕获带有颜色的输出的一种方法。 运行script会启动一个bash会话,其中所有原始输出都会被捕获到一个文件中(默认命名为typescript)。


31
一个例子:script -q /dev/null ls | cat - mitnk
2
这会导致生成的文件包含颜色代码(当然);有没有办法以一种利用颜色代码并在终端中正确显示颜色的方式打印文件?我尝试过 echo -e $(< filename),但似乎不起作用。 - Kyle Strand
1
实际上,“echo -e $(<filename)”似乎确实可以着色输出,但由于某种原因,输出的第一部分似乎被“Script done on <DATE>”所遮挡。 - Kyle Strand
另一个例子: script<enter for new shell> lolcat /etc/motd > /tmp/color_motd 然后根据需要编辑 typescript 文件并删除开头和结尾的输出。 - NoelProf
如果需要,可以使用https://stackoverflow.com/a/22528648/4288043将其转换为PDF。 - cardamom
显示剩余4条评论

51

重定向不会去除颜色,但是很多命令会检测它们是否在向终端输出内容,如果不是,则默认不显示颜色。例如,在Linux上,ls --color=auto(在许多地方都别名为简单的ls)将不会在输出到管道或文件时产生颜色代码,但是ls --color则会。许多其他工具也有类似的覆盖标志来使它们保存带有颜色的输出到文件中,但这都是针对具体工具的。

即使你已经将颜色代码保存在文件中,要想看到它们,你需要使用一个能够保留颜色代码的工具。 less 有一个-r标志来以“原始”模式显示文件数据;这样可以显示颜色代码。 编辑:稍新一些的版本还有一个-R标志,专门处理颜色代码并正确显示它们,对于像行包装/修剪之类的东西,它比原始模式具有更好的支持,因为 less 可以区分哪些是控制代码,哪些实际上是字符传送到屏幕上。


4
ls --color is the same as ls --color=always - you're thinking of ls --color=auto - Dennis Williamson
4
⁺¹,你刚刚解决了我们关于确定是应用程序决定是否将其重定向到文件,还是当shell进行重定向时它自身负责去除颜色ANSI符号的讨论。 - Hi-Angel

40

受到其他答案的启发,我开始使用script。不过我必须使用-c才能让它正常工作。所有其他答案,包括tee,不同的script示例对我都没有用。

上下文:

  • Ubuntu 16.04
  • 使用behave运行行为测试,并在测试期间使用Python的subprocess.check_call()启动shell命令

解决方案:

script --flush --quiet --return /tmp/ansible-output.txt --command "my-ansible-command"

开关的解释:

  • --flush 必须使用,否则输出将以大块的形式出现,无法实时观察
  • --quiet 禁止脚本工具自己的输出
  • -c, --command 直接提供要执行的命令,从我的命令到脚本的传输不起作用(没有颜色)
  • --return 使脚本传播我的命令的退出代码,以便我知道我的命令是否失败

1
最佳答案!谢谢。 - zoigo
2
我喜欢它甚至可以使用参数。为了在仍然将内容写入文件的同时抑制终端输出,可以在命令结尾处添加> /dev/nullscript --flush --quiet --return /tmp/ansible-output.txt --command "my-ansible-command" > /dev/null)。 - Cameron Hudson
2
在日志文件末尾添加内容,请加上“-a”标志。 - Micah Henning

19

我发现在将输出通过管道传输到 less 中,使用 script 无法保留颜色(less 的显示会出现问题,退出后 bash 也会受到影响),因为 less 是交互式的。即使退出后,script 仍然会导致来自 stdin 的输入出现问题。

所以,不要运行以下命令:

script -q /dev/null cargo build | less -R

在管道到 less 之前,我将 /dev/null 重定向到它:

script -q /dev/null cargo build < /dev/null | less -R

所以现在脚本不会干扰stdin,并且能够准确地得到我想要的内容。它相当于 command | less,但同时还保留了颜色,并继续读取追加到文件中的新内容(我尝试的其他方法无法做到这一点)。


顺便说一下,只要管道在运行,script 就不会退出。所以在您上面的第一个命令(实际上是两个命令)中,它直到less退出才会退出。 - Wildcard
这太棒了。对我来说,一个主要的用例是阅读彩色的 grep 输出,它比我的屏幕高,这在没有像 less 这样可以让我连贯滚动的阅读器的情况下并不真正有意义。 - ijoseph
有什么想法可以让它与shell函数一起工作吗?它似乎无法与它们一起运行。我会得到"命令未找到"或空白的结果。 - MrE
@MrE 不行,因为script是一个可执行文件,所以它无法访问您的shell函数。您需要将它们包装在独立的脚本中。 - bfontaine
使用unbuffer更容易,它可以在管道传输到less和其他交互式命令时工作:https://dev59.com/dXM_5IYBdhLWcg3wZSE6#1410273 - wisbucky
该命令运行得非常好:script -q --return /dev/null < /dev/null | ls -alh - Sunding Wei

12

有些程序在意识到输出不是 TTY(即当您将它们重定向到另一个程序时)时,会移除着色。您可以强制某些程序使用颜色,并告诉分页程序打开着色,例如使用 less -R.


5

这个问题在超级用户社区帮助了我,当我的其他答案(涉及tee)无法工作时。它涉及使用unbuffer让命令认为它正在从shell中运行。

我使用sudo apt install expect tcl安装它,而不是使用sudo apt-get install expect-dev

具有讽刺意味的是,我需要在重定向apt输出时使用此方法。


-4

我使用tee:将命令的输出导入到tee文件名,它会保留颜色。如果您不想在屏幕上看到输出(这就是tee的作用:同时显示和重定向输出),那么只需将tee的输出发送到/dev/null

命令| tee文件名> /dev/null


2
你使用的 tee 版本是什么?tee 8.21(随附于Ubuntu 14.04)似乎默认不会给输出着色(在一个虚拟程序中测试了cmake + make)。 - thiagowfx
我刚在两台机器上测试了一下,一台是tee 8.21,另一台是tee 8.25。两者都可以正常工作。我执行了 echo "^[[32mhello^[[0m" | tee temp.txt > /dev/null 命令(其中 ^[ 是转义字符),然后使用 catod -c 命令检查了 temp.txt 文件。 - IpsRich
你认为这会怎么样?一个程序只能知道它正在向FIFO发出内容,它无法知道FIFO后面是否有“tee”或任何其他特定的程序。因此,如果该程序被配置为仅将颜色直接发送到TTY,则管道到tee将像管道到任何其他程序一样干扰它。 - Charles Duffy
这不是一个理论性的答案:我已经成功地使用它了!我不知道它是如何工作的,但在简单重定向失败的情况下,它对我有效。 - IpsRich
这绝对不适用于问题的目的。这仅在直接回显颜色时有效,如上面的评论所说,因为它不检查终端是否支持颜色,而只是回显所要求的任何内容。tee确实会更改终端,并影响检查终端是否交互式的程序,就像简单的直接操作一样。 - olivecoder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接