76

I want to know if there's any way to check if my program can output terminal output using colors or not.

Running commands like less and looking at the output from a program that outputs using colors, the output is displayed incorrectly, like this:

[ESC[0;32m0.052ESC[0m ESC[1;32m2,816.00 kbESC[0m]

2

6 Answers 6

90

The idea is for my application to know not to color the output if the program can't print, say, logging output from through a cron job to a file, no need to log colored output, but when running manually, i like to view the output colored

What language are you writing your application in?

The normal approach is to check if the output device is a tty, and if it is, check if that type of terminal supports colors.

In bash, that would look like

# check if stdout is a terminal...
if test -t 1; then

    # see if it supports colors...
    ncolors=$(tput colors)

    if test -n "$ncolors" && test $ncolors -ge 8; then
        bold="$(tput bold)"
        underline="$(tput smul)"
        standout="$(tput smso)"
        normal="$(tput sgr0)"
        black="$(tput setaf 0)"
        red="$(tput setaf 1)"
        green="$(tput setaf 2)"
        yellow="$(tput setaf 3)"
        blue="$(tput setaf 4)"
        magenta="$(tput setaf 5)"
        cyan="$(tput setaf 6)"
        white="$(tput setaf 7)"
    fi
fi

echo "${red}error${normal}"
echo "${green}success${normal}"

echo "${green}0.052${normal} ${bold}${green}2,816.00 kb${normal}"
# etc.

In C, you have to do a lot more typing, but can achieve the same result using isatty and the functions listed in man 3 terminfo.

3
  • I found that each $(tput setaf <#>)" needed to be wrapped in \[ \] to work properly. For example: white="\[$(tput setaf 7)\]. Without this, I experienced weird history editing behavior in vi mode in BASH 5.0.16(1)-release.
    – srdubya
    Feb 23, 2020 at 14:26
  • @srdubya Yes, if you're doing that in your bash prompt.
    – Mikel
    Feb 24, 2020 at 4:56
  • AFAIK you don't even need the 2nd check, tput colors, tput should only print escape codes if supported by the terminal. Aug 20, 2020 at 0:57
29

This should be enough:

$ tput colors

tput colors explained:

If you look at the manpage, you'ill notice this:

SYNOPSIS
       tput [-Ttype] capname [parms ... ]

And...

   capname
          indicates the capability from the terminfo database.  When term‐
          cap  support is compiled in, the termcap name for the capability
          is also accepted.

The termcap colors is in the terminfo database, so you can ask for it. If you have a zero exit status, then the termcap is compiled in. But if you have somethin like:

$ tput unknowntermcap
tput: unknown terminfo capability 'unknowntermcap'
$ echo $?
4

This shows that unknowntermcap doesn't exist. So, this:

$ tput colors
8
$ echo $?
0

Shows that your command was right.

Other useful ways:

  • In C, you can just use isatty and see if it's a TTY
  • See if it's a dumb terminal looking $TERM variable

Cheers

5
  • colors is not documented in the tput man page (!), so should I look for a number >= 8 in stdout or a return code of 0?
    – l0b0
    Mar 24, 2011 at 7:43
  • Seemed obvious, but your comment shows that it isn't. I'm adding that info (briefly, colors is a capability of terminfo database)
    – D4RIO
    Mar 24, 2011 at 15:36
  • 1
    The colors capability is documented in terminfo(5). Testing using tput -T dumb colors, tput -T vt220 colors, tput -T linux colors, tput -T xterm colors suggests common values are -1 (no color support) and 8 (8 colors). Note that this only applies after checking the output device is a terminal (e.g. [ -t 1 ] or isatty).
    – Mikel
    Mar 25, 2011 at 0:20
  • 2
    Note that tput colors returns what the local terminal database thinks of the terminal. This may or may not correspond to what the terminal can actually do, especially for a terminal type like xterm which comes in many variants (ranging from black and white to 256 colors). Nov 1, 2011 at 22:37
  • At the time of writing this question, and some years afterward, relying upon the exact value of the capability was problematic, because a 16-bit compatibility requirement in the data file format prevented it from correctly reporting 24-bit colour. Since 2018, a new file format can handle 32-bit numeric terminfo capabilities. stackoverflow.com/a/36163656/340790
    – JdeBP
    Aug 17, 2020 at 14:10
10

The idea is for my application to know not to color the output if the program can't print, say, logging output from through a cron job to a file, no need to log colored output, but when running manually, i like to view the output colored.

For this use case, what programs typically do (e.g. GNU ls or GNU grep with --color=auto) is to use colors if their output is going to a terminal, and no colors otherwise. Terminals that don't support ANSI color-changing sequences are rare enough that it's acceptable to make their users override the default choice. In any case, make sure your application has an option to force colors on or off.

In a shell script, use [ -t 1 ] to test if standard output is a terminal.

# option processing has set $color to yes, no or auto
if [ $color = auto ]; then
  if [ -t 1 ]; then color=yes; else color=no; fi
fi

From a program using the C API, call isatty(1).

# option processing has set use_color to 0 for no, 1 for yes or 2 for auto
if (use_color == 2) use_color = isatty(1);
6
  • Unfortunately there seem to be specific situations where test -t 1 fails even though colours are supported. To give a concrete example, I have a “post-install” script in an RPM package (generated by fpm). When running the script via yum install my.rpm (interactively), test -t 1 returns 1 even though colours are correctly displayed. Any idea why that might be? Feb 15, 2022 at 15:26
  • (I should note that the identical script correctly detects colours when generating a DEP or APK package via fpm, the issue only manifests on CentOS with RPM packages, so I’m fairly confident that this isn’t simply an error in the script.) Feb 15, 2022 at 15:35
  • 1
    @KonradRudolph test -t 1 checks if the output is a terminal. It's impossible to fully reliably know whether the output is going to a place that supports color changing escape sequences. For example, some terminals don't support colors (termcap/terminfo can help here, but it isn't 100% reliable either). In the other direction, it's impossible to distinguish my_code | less (doesn't support colors) from my_code | less -R (does support colors), or to know how the log file will be viewed in my_code >log.txt. Feb 15, 2022 at 15:45
  • 1
    @KonradRudolph I guess the yum installation is piping the output, maybe | tee log.txt or some such. If so then presumably either you're not supposed to use colored output, or you're supposed to force colors on (--color=always rather than --color=auto) if you want to have colors. Feb 15, 2022 at 15:46
  • @KonradRudolph The value of shell has no influence on whether the process run by subprocess.run and friends has a terminal on stdout/stderr. Only whether the Python process itself has a terminal on stdout/stderr, and obviously redirection options. Feb 15, 2022 at 16:17
5

Running commands like less and looking at the output from a program that outputs using colors, the output is displayed wrong, like

[ESC[0;32m0.052ESC[0m ESC[1;32m2,816.00 kbESC[0m]

Try using less --RAW-CONTROL-CHARS.

In this example, I am using logtool, which prints output using colors.

Without --RAW-CONTROL-CHARS:

$ head -20 /var/log/messages | logtool | less
ESC[0mESC[0;37mMar 20 11:43:52ESC[0mESC[1;36m host1ESC[0mESC[0;37m rsyslogd:ESC[0m ^GESC[0;31mlast message repeated 14 timesESC[0mESC[0m

With --RAW-CONTROL-CHAR:

$ head -20 /var/log/messages | logtool | less --RAW-CONTROL-CHARS
Mar 20 11:43:52 host1 rsyslogd: ^Glast message repeated 14 times

Imagine this is in pretty colors. Also, I am not sure why that ^G is being displayed.

4

That would be the fault of less not being set to interpret ANSI escapes; look for R in $LESSOPTS. As for determining if the system knows your terminal can deal with colors, tput colors will output either the number of colors it supports or -1 if it doesn't support colors. (Note that some terminals may use xterm instead of xterm-color as their terminal description, but still support colors.)

1
  • The idea is for my application to know not to color the output if the program can't print, say, logging output from through a cron job to a file, no need to log colored output, but when running manually, i like to view the output colored. Mar 23, 2011 at 15:28
2

If you want to add color to output but only when colors are supported, you can simply use tput. http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x405.html

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .