less emulate a TTY to preserve piped color output



When you pipe something through less, the program usually discards color codes because it's not outputting to a TTY. So you have to add --color=always to the options for it to work.

ls -l --color=always | less
grep -R asdf --color=always | less

What's worse is that sometimes things don't even support that option, so there's actually no way to force color output to a pipe.

Is there a (relatively) easy way to make less emulate a TTY so that I don't have to specify --color=always to every program when things get piped to it, and it automatically displays color output when possible?


Posted 2012-02-03T22:47:12.907

Reputation: 1 390

1I don't ever recall seeing a TTY that printed in other than black. – Daniel R Hicks – 2012-02-03T23:10:16.107



It's not less that needs to change. The output of your other programs is being redirected to a pipe. Those programs detect that their output is not being sent to a tty and they disable their coloring. You're stuck with having to do something special with the source programs to color their output even when redirected to a pipe.

I think I have a solution for the programs that do not support a --color=always option. The unbuffer command creates a pty and sends the output of its argument program to that pty, therefore the argument program thinks its output is going to a tty and colors it.

I tried the following as an experiment and it worked. I couldn't think of any programs that color their output by default.

$ unbuffer ls --color=auto | cat

Also, don't you have to use the -r option with less to get it to display color? I also tried this:

$ unbuffer ls --color=auto | less -r


Posted 2012-02-03T22:47:12.907

Reputation: 29 085


on FreeBSD you can:

env CLICOLOR_FORCE=yes ls -l | less -R

or you can set/override options (csh/tcsh):

alias less less -R
setenv  LS_COLORS "no=00:fi=00:di=01;36:ln=01;37;44:pi=40;33:so=01;35"
setenv  LS_COLORS "$LS_COLORS":"bd=40;33;01:cd=40;33;01:or=40;31;01"
setenv  LS_COLORS "$LS_COLORS":"ex=01;32;40:*.tar=01;31:*.tgz=01;31"
setenv  LS_COLORS "$LS_COLORS":"*.arj=01;31:*.taz=01;31:*.lzh=01;31"
setenv  LS_COLORS "$LS_COLORS":"*.zip=01;31:*.z=01;31:*.Z=01;31"
setenv  LS_COLORS "$LS_COLORS":"*.gz=01;31:*.deb=01;31:*.jpg=01;35"
setenv  LS_COLORS "$LS_COLORS":"*.gif=01;35:*.bmp=01;35:*.ppm=01;35"
setenv  LS_COLORS "$LS_COLORS":"*.tga=01;35:*.xbm=01;35:*.xpm=01;35"
setenv  LS_COLORS "$LS_COLORS":"*.tif=01;35:*.mpg=01;37:*.avi=01;37"
setenv  LS_COLORS "$LS_COLORS":"*.gl=01;37:*.dl=01;37:*.tex=01;35"
setenv  LS_COLORS "$LS_COLORS":"*.ps=01;35"
setenv  LS_COLORS "$LS_COLORS":"*.php=01;33"
setenv  LS_COLORS "$LS_COLORS":"*.sh=00;31"
setenv  LS_COLORS "$LS_COLORS":"*.txt=01;37:*.conf=01;37:*.config=01;37"
setenv  LSCOLORS GxExcxdxCxegedabagacad

in ~/.cshrc


Posted 2012-02-03T22:47:12.907

Reputation: 31


If the program uses isatty to determine whether to use color or not,
one way to do it is to override it by using LD_PRELOAD

Create a version of isatty that always returns true.

echo "int isatty(int x) { (void) x; return 1 ;}" > isatty_override.c

Compile it and create a shared library.

gcc -c -fPIC isatty_override.c -o isatty_override.o
gcc isatty_override.o -shared -o isatty_override.so

Use the LD_PRELOAD environment variable to load the shared library.

LD_PRELOAD=./isatty_override.so ls -l | less


Posted 2012-02-03T22:47:12.907

Reputation: 21


There isn't any way to make less allocate a pty, though, so programs that depend on a TTY for deciding to output color or not need to be manually told. Sorry.

Daniel Pittman

Posted 2012-02-03T22:47:12.907

Reputation: 3 510


On FreeBSD's Bash shell, to get colored piping working using less do the following...

$ export CLICOLOR_FORCE=yes
$ ls -G | less -R

You can add the export command to your .bashrc or .bash_profile.

Jim Yuzwalk

Posted 2012-02-03T22:47:12.907

Reputation: 1