16

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...?)

Wildcard
  • 35,316
  • 26
  • 130
  • 258
Captain Man
  • 1,156
  • 3
  • 12
  • 25
  • 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 May 21 '16 at 00:33

4 Answers4

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:

Thomas Dickey
  • 75,040
  • 9
  • 171
  • 268
  • 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](http://wiki.bash-hackers.org/syntax/pe) is all I found, but I'm not sure it's what is happening here. Thanks! – Captain Man Apr 06 '16 at 13:11
2

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.

roaima
  • 107,089
  • 14
  • 139
  • 261
2

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.

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
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.

jimmij
  • 46,064
  • 19
  • 123
  • 136