74

A lot of times (not always) the stdout is displayed in colors. Normally I keep every output log in a different file too. Naturally in the file, the colors are not displayed anymore.

Console color output example

I'd like to know if there's a way (in Linux) to write the output to a file with colors. I'm trying to use tee to write the output of vagrant to a file, this way I can still see the output (when it applies). I want to use it specifically for vagrant (it may change in the future, of course...)

CJBS
  • 15,147
  • 6
  • 86
  • 135
AAlvz
  • 1,059
  • 2
  • 9
  • 15
  • 6
    Usually the program doing the writing determines whether it's writing to a terminal, and if it's not it won't use colours. So it's probably a matter of telling the program in question to use colours anyway. Some programs have something like `--color always`, but there's no standard. – Biffen Dec 10 '14 at 09:54

10 Answers10

65

Since many programs will only output color sequences if their stdout is a terminal, a general solution to this problem requires tricking them into believing that the pipe they write to is a terminal. This is possible with the script command from bsdutils:

script -q -c "vagrant up" filename.txt

This will write the output from vagrant up to filename.txt (and the terminal). If echoing is not desirable,

script -q -c "vagrant up" filename > /dev/null

will write it only to the file.

Wintermute
  • 42,983
  • 5
  • 77
  • 80
  • I really like this answer and it's the best one so far, but isn't this a little overkilled? :) – AAlvz Dec 12 '14 at 16:39
  • 2
    `script` is surprisingly light, actually. Mostly it just opens a pty, spawns a shell and pipes the output to you. It's some 500 lines of C code, all in all. – Wintermute Dec 12 '14 at 17:18
  • Thanks! I like a lot this solution. Script has a lot of potential! – AAlvz Dec 14 '14 at 18:33
  • 1
    This doesn't work - at least with with the script from bsdutils 1:2.25.2-6 on debian. "ls -l" gives colour. "script -q -c 'ls -l'" does not. – Draemon Aug 05 '16 at 01:31
  • @Draemon: Maybe aliases don't work in the script's shell? – choroba Aug 06 '16 at 20:15
  • 1
    the brew version of script does not have the -c operator. – Dobler Jan 28 '17 at 10:59
  • 10
    For Mac OSX: `script -q filename.txt vagrant up` works. `usage: script [-adkpqr] [-t time] [file [command ...]]` – jezmck Jun 19 '17 at 15:11
  • 2
    I know I'm late to the party, but this prepends `Script started on Blah blah blah...` to the file even with the `-q` flag. Is there a way to avoid this? – Aaron N. Brock Apr 09 '18 at 15:27
  • 1
    Apparently you cannot get rid of that header, @AaronN.Brock . :( Please see https://github.com/karelzak/util-linux/commit/7ba1ca0d05bd35754e78b22ee470c9828b179c11 for the reason. – Greg Dubicki Oct 04 '20 at 10:33
  • ...or you can, after all, @AaronN.Brock! Please see [this answer](https://stackoverflow.com/a/61887597/2693875). – Greg Dubicki Mar 19 '22 at 23:27
14

You can save the ANSI sequences that colourise your output to a file:

echo a | grep --color=always . > colour.txt
cat colour.txt

Some programs, though, tend not to use them if their output doesn't go to the terminal (that's why I had to use --color-always with grep).

choroba
  • 231,213
  • 25
  • 204
  • 289
  • 1
    do you know if there's a way to do this with `tee`? – AAlvz Dec 10 '14 at 15:42
  • @AAlvz: What happened when you tried? `echo a | grep --color=always . | tee colour.txt` – choroba Dec 10 '14 at 15:47
  • 3
    It's always red no matter what =/ – AAlvz Dec 10 '14 at 15:56
  • @AAlvz: Sure, that's how `grep` is configured by default. I though that was your question: how to get colour into a file. If you want to know how to colourise output, it's a different question. – choroba Dec 10 '14 at 16:00
  • Well, the Output of vagrant comes with colors. I just want to see the same colors in the outputfile. Is it possible? – AAlvz Dec 10 '14 at 16:05
  • 1
    @AAlvz: Well, the Output of `grep` in my example comes with colours, and you were able to see the same colours in the outputfile. Now, you just have to investigate whether there is an option to vagrant similar to `--color=always`, if it's sensitive to terminal/file output. – choroba Dec 10 '14 at 16:07
9

In Ubuntu, you can install the package bsdutils to output to a text file with ANSI color codes:

script -q -c "ls --color=always" /tmp/t

Install kbtin to generate a clean HTML file:

ls --color=always | ansi2html > /tmp/t.html

Install aha and wkhtmltopdf to generate a nice PDF:

ls --color=always | aha | wkhtmltopdf - /tmp/t.pdf

Use any of the above with tee to display the output also on the console or to save a copy in another file. Example:

ls --color=always | tee /dev/stderr | aha | wkhtmltopdf - /tmp/test.pdf
Ivan Ogai
  • 1,406
  • 15
  • 9
  • 1
    In the RedHat/Rocky/CentOS world, script is usually already installed, from the package util-linux. The ansi2html utility is not available anywhere, but an apparently equivalent utility is ansifilter, which comes from the ansifilter RPM. It can generate various output formats, including LaTeX, which can then be processed into a PDF. – Kevin Keane May 05 '22 at 01:04
  • 1
    This plus `catimg` just made for a really fun half hour. Thank you! – Thomas Ingham Sep 03 '22 at 03:29
7

You can also color your output with echo with different colours and save the coloured output in file. Example

echo -e '\E[37;44m'"Hello World" > my_file

Also You would have to be acquainted with the terminal colour codes

Using tee

< command line > |tee -a 'my_colour_file'

Open your file in cat

cat 'my_colour_file'

Using a named pipe can also work to redirect all output from the pipe with colors to another file

for example

Create a named pipe

mkfifo pipe.fifo

each command line redirect it to the pipe as follows

<command line> > pipe.fifo

In another terminal redirect all messages from the pipe to your file

cat pipe.fifo > 'my_log_file_with_colours'

open your file with cat and see the expected results.

repzero
  • 8,254
  • 2
  • 18
  • 40
  • The problem here is that the Vagrant output has colors already... I'm currently using `tee` to save them to a file – AAlvz Dec 11 '14 at 12:57
  • good observation..nevertheless, it still demonstrates the principle that coloured output can be saved. Answer edited to correct this minor detail. – repzero Dec 11 '14 at 20:54
  • I'm also sure that it can be done... But I still don't know how. If you come with an idea, please tell me. – AAlvz Dec 12 '14 at 10:14
  • Okay I edited my answer to demonstrate another of way using named pipes to redirect all coloured output for each command line to a named pipe – repzero Dec 12 '14 at 11:10
  • I was so confident that this would work but it doesn't :/ (no colors) – AAlvz Dec 12 '14 at 16:35
  • OK..it is working on my side..However to make this a little more easier try the "tee" command. I further edited my answer to include how to use tee without creating named pipes – repzero Dec 12 '14 at 20:22
  • note:for every command you will have to pipe the output to tee, which will append the lines to the file – repzero Dec 12 '14 at 20:26
6

I found out that using the tool called ansi2html.sh

Is the most simple way to export colorful terminal data to html file,

The commands to use it are:

ls --color=always | ansi2html.sh --palette=solarized > ~/Desktop/ls.html
  • All is needed is to send the output using a pipe and then output the stdout to simple html file
Pini Cheyni
  • 5,073
  • 2
  • 40
  • 58
3

Solution

$ script -q /dev/null -c "your command" > log.txt
$ cat log.txt

Explanation

According to the man page of script, the --quit option only makes sure to be quiet (do not write start and done messages to standard output). Which means that the start and done messages will always be written to the file.

In order to utilize script and discard the output file at the same file, we can simply specify the null device /dev/null to it! Also, redirect the output to our desired destination and the color content will be written to the destination.

WinDerek
  • 83
  • 7
1

I was trying out some of the solutions listed here, and I also realized you could do it with the echo command and the -e flag.

$ echo -e "\e[1;33m This is yellow text \e[0m" > sample.txt

Next, we can view the contents of our sample.txt file.

$ cat sample.txt

Click link to see the output in yellow

Additionally, we can also use tee and pipe it with our echo command:

echo -e "\e[1;33m This is yellow text \e[0m" | tee -a sample.txt
1

In the RedHat/Rocky/CentOS family, the ansi2html utility does not seem to be available (except for Fedora 32 and up). An equivalent utility is ansifilter from the EPEL repository. Unfortunately, it seems to have been removed from EPEL 8.

script is preinstalled from the util-linux package.

To set up:

yum install ansifilter -y

To use it:

ls --color=always | ansifilter -H > output.html

To generate a pretty PDF (not tested), have ansifilter generate LaTeX output, and then post-process it:

ls --color=always | ansifilter -L | pdflatex >output.pdf

Obviously, combine this with the script utility, or whatever else may be appropriate in your situation.

Kevin Keane
  • 1,506
  • 12
  • 24
0

On macOS, script is from the BSD codebase and you can use it like so:

script -q /dev/null mvn dependency:tree mvn-tree.colours.txt

It will run mvn dependency:tree and store the coloured output into mvn-tree.colours.txt

The tee utility supports colours, so you can pipe it to see the command progress:

script -q /dev/null mvn dependency:tree | tee mvn-tree.colours.txt

To get the script manual you can type man script:

SCRIPT(1)                 BSD General Commands Manual                SCRIPT(1)

NAME
     script -- make typescript of terminal session

SYNOPSIS
     script [-adkpqr] [-F pipe] [-t time] [file [command ...]]
pyb
  • 4,813
  • 2
  • 27
  • 45
0

The solution that worked for me on MacOS was with using script as follows:

#!/bin/bash

SILENT_LOG=/tmp/silent_log_$$.txt
trap "/bin/rm -f $SILENT_LOG" EXIT

function silent {
    script -q $SILENT_LOG $* > /dev/null;
    cat "${SILENT_LOG}";
}

silent npm run lint

The -q prevents script from writing the start and end messages to the file. It seems script can only take a single command, so writing it as a function works best as shown above.

RivasCVA
  • 91
  • 2
  • 8