150
ls -l --color=auto | tee output.log

Without pipe/tee it's colored. How can I make it so that it stays colored while using tee (can be colored only on the screen, I don't care about colors in logs).

6 Answers6

200

Simply insert unbuffer before any command to make it think it is writing to an interactive output even if it is actually piping into another executable. This will preserve color in the case of ls.

For example

unbuffer ls -l --color=auto | tee output.log

If you don't already have it installed, on Ubuntu and other Debian-ish Linux distributions you can install unbuffer by doing.

sudo apt-get install expect-dev
Eamonn O'Brien-Strain
  • 2,116
  • 1
  • 13
  • 4
20

I'll expand the script solution given in the comment of the accepted answer. Using script may be useful in case you can't or don't want to install the expect package that contains the unbuffer command.

Print ls output to stdout and file with color codes:

script -efq output.log -c "ls -l --color=auto"

where (man script):

  -e, --return
         Return the exit code of the child process.  Uses the same
         format as bash termination on signal termination exit code is 128+n.
  -f, --flush
         Flush output after each write.  This is nice for telecooperation:
        one person does `mkfifo foo; script -f foo', and another can 
        supervise real-time what is being done using `cat foo'.
  -q, --quiet
         Be quiet (do not write start and done messages to either 
         standard output or the typescript file).

View the output file with colors:

less -r output.log
20

Use the ls option --color=always

--color=auto will not color output to a pipeline - for obvious reasons.

The ls man page says the following:

With --color=auto, color codes are output only if standard output is connected to a terminal (tty).

6

script -efq -c "ls --color=auto" >(cat) | tee output.log

For convenience I created this script:

#!/usr/bin/bash
script -efq -c "$*" >(cat)

call it say unbuff and then

unbuff ls --color=auto | tee output.log
nadapez
  • 250
3

Here is a function based off this clean answer that I couldn't fit in the comments.

output()
{
    output_file=$1
    shift
    command=$@
script -efq $output_file -c "$command"
less $output_file

}

Usage

output file command
mcp
  • 160
2
$ pipe-with-color(){ script -efq -O /dev/null -c "$@";}
$ pipe-with-color "git log origin/trunk.. --format='%Cred%h%Creset␟%C(cyan)%an%Creset␟%H␟%Cblue%f%Creset'" | git name-rev --annotate-stdin --always --name-only | column -t -s'␟'

upper cmd GIF demo

pipe output and keep colors, but do not make a temp file(write the log out to /dev/null by -O option).

The upper example shows how it can be used: first, pipe the git log ... colored output to git name-rev to make it human readable(prev cmds output color keeps), then pipe again to indent for readability, the final result also keeps the git log ... output color.