18

In people's '.*rc' files I see online or in various code, I tend to see a lot of people who manually use ANSI escape sequences instead of using tput.

I had the understanding that tput is more universal/safe, so this makes me wonder:

Is there any objective reason one should use escape sequences in place of tput? (Portability, robustness on errors, unusual terminals...?)

3
  • On the flip side of the portability question, MobaXterm will work with printf and ANSI escape sequences, but tput fails (at least on my box).
    – Wildcard
    Commented May 21, 2016 at 0:33
  • Can tput be assumed to be pre-installed on any unix-like distrubtion? Somehow I would prefer to use escape codes directly but can't figure out if any of my systems would not have tput. Maybe Cygwin? Commented Jul 7 at 7:59
  • 1
    @SridharSarnobat I'm not sure. That might be a good follow-up question to post though. My gut feeling says yes. Also, when I wrote this question I was using Cygwin so I assume it has tput by default. Commented Jul 9 at 1:05

4 Answers 4

10

tput can handle expressions (for instance in sgr and setaf) which the typical shell-scripter would find less than usable. To get an idea of what is involved, see the output from infocmp with the -f (formatting) option applied. Here is one of examples using those strings from xterm's terminfo descriptions:

xterm-16color|xterm with 16 colors,
        colors#16,
        pairs#256,
        setab=\E[
                %?
                        %p1%{8}%<
                        %t%p1%{40}%+
                %e
                        %p1%{92}%+
                %;%dm,
        setaf=\E[
                %?
                        %p1%{8}%<
                        %t%p1%{30}%+
                %e
                        %p1%{82}%+
                %;%dm,
        setb=
                %p1%{8}%/%{6}%*%{4}%+\E[%d%p1%{8}%m%Pa
                %?%ga%{1}%=
                        %t4
                %e%ga%{3}%=
                        %t6
                %e%ga%{4}%=
                        %t1
                %e%ga%{6}%=
                        %t3
                %e%ga%d
                %;
                m,
        setf=
                %p1%{8}%/%{6}%*%{3}%+\E[%d%p1%{8}%m%Pa
                %?%ga%{1}%=
                        %t4
                %e%ga%{3}%=
                        %t6
                %e%ga%{4}%=
                        %t1
                %e%ga%{6}%=
                        %t3
                %e%ga%d
                %;
                m,
        use=xterm+256color,
        use=xterm-new,

The formatting splits things up - a script or program to do the same would have to follow those twists and turns. Most people give up and just use the easiest strings.

The 16-color feature is borrowed from IBM aixterm, which maps 16 codes each for foreground and background onto two ranges;

  • foreground onto 30-37, and 90-97
  • background onto 40-47, and 100-107

A simple script

#!/bin/sh
TERM=xterm-16color
export TERM
printf '    %12s %12s\n' Foreground Background
for n in $(seq 0 15)
do
    F=$(tput setaf $n | cat -v)
    B=$(tput setab $n | cat -v)
    printf '%2d  %12s %12s\n' $n "$F" "$B"
done

and output show how it works:

      Foreground   Background
 0        ^[[30m       ^[[40m
 1        ^[[31m       ^[[41m
 2        ^[[32m       ^[[42m
 3        ^[[33m       ^[[43m
 4        ^[[34m       ^[[44m
 5        ^[[35m       ^[[45m
 6        ^[[36m       ^[[46m
 7        ^[[37m       ^[[47m
 8        ^[[90m      ^[[100m
 9        ^[[91m      ^[[101m
10        ^[[92m      ^[[102m
11        ^[[93m      ^[[103m
12        ^[[94m      ^[[104m
13        ^[[95m      ^[[105m
14        ^[[96m      ^[[106m
15        ^[[97m      ^[[107m

The numbers are split up because aixterm uses the 30-37 and 40-47 ranges to match ECMA-48 (also known as "ANSI") colors, and uses the 90-107 range for codes not defined in the standard.

Here is a screenshot with xterm using TERM=xterm-16color, where you can see the effect.

enter image description here

Further reading:

3
  • 1
    I may be proving your point, but what is the deal with these expressions? From looking at the manual for infocmp I realize they are if-then-else statements... but I've never seen this and I'm having trouble googling for it, this is all I found, but I'm not sure it's what is happening here. Thanks! Commented Apr 6, 2016 at 13:11
  • May i ask how to understand the infocmp -f output? Manual says they are if/then/else/endif expressions. What do the % codes mean? Any resources to look them up? Thank you.
    – midnite
    Commented Dec 9, 2023 at 18:45
  • See description of %? expr %t thenpart %e elsepart %; in terminfo(5). Commented Dec 9, 2023 at 19:38
4

Coming from a time when UNIX platforms could have a variety of devices attached to them, I still much prefer tput and its friends over literal escape sequences.

I think the real reason is that most people simply don't know about tput and its associated terminfo/termcap files and libraries.

3

The advantage of tput is that it looks up what the terminal can do and how, which allows it to get correct information for your terminal. The downside of tput is that it looks up what the terminal can do and how, which can lead it to get incorrect information for your terminal.

tput looks for information in the terminfo database, or on older systems in the termcap database. The way this normally works is that the system sets the TERM environment variable to a terminal name when the terminal starts. With a physical terminal, this is the job of getty. With a terminal emulator, this is the job of the terminal emulator program. Programs running in the terminal, including tput, look up the value of TERM in the termcap or terminfo database, both of which map terminal names to “capabilities”. Terminal capabilities indicate what the terminal can do and how: whether it can do automatic line wrap, how many columns it has, what character sequence the Left key sends, what character sequence to send to the terminal to move the cursor left, etc.

All this is great because it allows programs and terminals to work independently. The system just has to maintain a file containing the capabilities of each available terminal type. For physical terminals, this file would basically be the driver for the terminal. For terminal emulators, this file should be distributed with the terminal emulator program. (There isn't necessarily one file per terminal type, but that's just an implementation detail which is not relevant here.)

This breaks down when you consider remote logins. Programs such as rlogin and ssh are terminal emulators on the server, but all they do is relay to the “real” terminal on the client side. So they don't have their own terminal type, they just transmit the TERM environment variable, so that remote programs running in a terminal will know the capabilities of the terminal. However, programs running on the server then look up the terminal name on the server's termcap/terminfo database, which may not know about the terminal types available on the client.

In the 1970s, ANSI standardized a set of capabilities which was eventually followed by almost all physical terminals. Terminal emulators have continued following this standard. When all terminals have the same capabilities, the terminal database isn't really useful. So people got into the habit of hard-coding terminal escape sequences, either because they didn't know about the terminal database or simply because it was easier: you can just consult your terminal's documentation or experiment, you don't need to also learn the termcap/terminfo interface.

Furthermore ,in the days when a remote login was usually to another machine on the same site administered by the same people, it wasn't hard to ensure that all systems would know about all other systems' terminals. But on the Internet, this doesn't scale. Today, almost all graphical terminal emulators set TERM to xterm, because that's a terminal name that you're sure is known everywhere. Some set TERM to xterm-256color, which can get you into trouble on some systems that don't know this name.

The problem with setting TERM to a value that's widely supported, rather than one that exactly describes the capabilities of the terminal, is that you end up missing out on features that are not present in ancient versions of xterm. For example, ancient xterm only supported 8 colors, so on many systems, the termcap/terminfo database entry for xterm says that the number of colors is 8. So how do you use other colors? You can define a new terminal name such as xterm-256color, which many systems do nowadays, but not all. And it isn't even accurate: a modern xterm supports 24-bit colors. So, if you want 256 colors, tput may get you in trouble with remote logins (assuming you do have a xterm-256color on your system), and if you want to use 24-bit colors, tput won't help you.

In conclusion, tput gives you portability on unusual terminals at the expense of features. Using escape sequences directly can give you portability to the terminals you actually use, without limitation on features.

1

One of the reason is that tput is the external command, so may run slower than built-in shell escape codes. Another thing is that one can easily create one liners combining ANSI escape codes with shell specific escaped characters, such as in bash prompt for example:

PS1='\[\033[1;32m\]\u@\h\[\033[1;34m\] \w >\[\033[0m\] '

similarly in zsh:

PS1=$'%{\e[1;32m%}%n@%m%{\e[1;34m%} %3~> %{\e[0m%}'

Here everything is clear and compact. With tput one would need to split it to multiple lines or make it much longer and complex line, executing tput multiple times, etc.

3
  • 6
    With tput you can still do oneliners, PS1="$(tput setaf 2)\u@\h$(tput reset) > Commented Apr 5, 2016 at 19:48
  • 5
    Actually that would be $(tput sgr0) for the ending, but agreeing that tput is an improvement. Commented Apr 5, 2016 at 22:16
  • You can also run tput once at start up and embed the output directly in PS1. There's no need to run it every time PS1 is expanded. Commented Dec 10, 2023 at 12:05

You must log in to answer this question.

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