How to check if Bash can print colors
Solution 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
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
.
Solution 2
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
Solution 3
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);
Solution 4
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.
Solution 5
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.)
Related videos on Youtube
Angelo Vargas
Updated on September 17, 2022Comments
-
Angelo Vargas over 1 year
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]
-
Gilles 'SO- stop being evil' over 12 years
-
Franklin Yu over 6 years
-
-
Angelo Vargas about 13 yearsThe 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.
-
l0b0 about 13 years
colors
is not documented in thetput
man page (!), so should I look for a number >= 8 in stdout or a return code of 0? -
D4RIO about 13 yearsSeemed obvious, but your comment shows that it isn't. I'm adding that info (briefly, colors is a capability of terminfo database)
-
Mikel about 13 yearsThe
colors
capability is documented in terminfo(5). Testing usingtput -T dumb colors
,tput -T vt220 colors
,tput -T linux colors
,tput -T xterm colors
suggests common values are-1
(no color support) and8
(8 colors). Note that this only applies after checking the output device is a terminal (e.g.[ -t 1 ]
orisatty
). -
Gilles 'SO- stop being evil' over 12 yearsNote 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 likexterm
which comes in many variants (ranging from black and white to 256 colors). -
srdubya about 4 yearsI 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. -
Mikel about 4 years@srdubya Yes, if you're doing that in your bash prompt.
-
JdeBP almost 4 yearsAt 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
-
Thomas Guyot-Sionnest over 3 yearsAFAIK you don't even need the 2nd check,
tput colors
, tput should only print escape codes if supported by the terminal. -
Konrad Rudolph over 2 yearsUnfortunately 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 viayum install my.rpm
(interactively),test -t 1
returns 1 even though colours are correctly displayed. Any idea why that might be? -
Konrad Rudolph over 2 years(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.)
-
Gilles 'SO- stop being evil' over 2 years@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 distinguishmy_code | less
(doesn't support colors) frommy_code | less -R
(does support colors), or to know how the log file will be viewed inmy_code >log.txt
. -
Gilles 'SO- stop being evil' over 2 years@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. -
Gilles 'SO- stop being evil' over 2 years@KonradRudolph The value of
shell
has no influence on whether the process run bysubprocess.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. -
Konrad Rudolph over 2 yearsYes, never mind, that was nonsense (made a mistake).