4

From what I know, a well-behaved command-line program should examine the $TERM environment variable get the name of the terminal emulator, look up its entry in the terminfo database, and then use those escape codes to control terminal settings such as colours, fonts, styles, erasing the screen, and setting the cursor position.

However, I'm a lazy programmer, and if I want to make some text green, then by far the easiest thing to do is to embed ANSI escape codes directly in my program:

print("\033[32mhi\033[0m")

Changing the terminal colour this way is simple to implement, frees me from having to learn a new dependency (such as ncurses), frees me from running any external programs (such as tput), and lets me write my program in any language that has strings, rather than any language that has a terminal library.

The idealist in me thinks that it's always better to rely on a standard than to rely on one particular implementation. My macOS installation comes with over two thousand terminal definitions in /usr/share/terminfo. The pragmatist, on the other hand, has noticed that everybody has been embedding ANSI codes for years now, and everything seems to be fine.

I commonly see code that avoids using a helper library and just uses ANSI codes directly, or software that just checks if $TERM is anything other than dumb, or software that doesn't check $TERM at all. And I very rarely see anybody complaining about this, or requesting support for other terminal types.

Furthermore, I've seen many, many posts on the Internet that make no mention of any other terminal types or escape codes, referring to the ANSI set as "how to do bold and colours in a terminal". It really seems like all other escape code sets have died out, and that ANSI codes (or ECMA-48 codes, or VT102 codes) have become the de-facto standard that the development community has settled on.

So, my question is: if I'm writing command-line software in 2019, is it safe to assume that it will only be used in terminals that speak ANSI?


Edit: People have proposed calling tput at runtime to print colours to the screen without having to deal with terminfo at all. This works, and is a good solution in many cases, but in my opinion it introduces an unnecessary runtime cost, as it has to execute a separate binary multiple times right as my program starts.

  • 2
    "most of the time" is not the same as "all of the time". Something that only works some (or even most) of the time is broken. To belabour this point, consider the question: "is it safe to drive my car without working brakes because most of the time I can just take my foot off the accelerator and roll to a stop?". Often relatively harmless, occasionally catastrophic. so: no problem, right? – cas Oct 23 '19 at 2:46
  • 2
    btw, you don't need to run tput repeatedly. You store the output of tput in variables and use the variables repeatedly, as in roaima's comment. you might need to switch between green and white text 1000 times but you only need to run tput twice - once for green="$(tput ...)" and once for white="$(tput ...)" – cas Oct 23 '19 at 23:46
  • 2
    I don't see the point of this question. Just announce you support a bunch of known good terminals (or terminal libraries like vte), and be done with it. – muru Nov 1 '19 at 12:51
  • 4
    I have found that terminal codes don't map cleanly between xterm, screen, and the Linux "console". Is that enough reason? – roaima Nov 1 '19 at 17:06
  • 2
    Turning colors on by default, or worse, hardcoding them (and assuming a dark background!) is already bad enough, I don't see how not supporting it all the terminal emulators can make it worse. But you're well within the trend -- to stop dmesg from spicing up my life with yellow text (on lightgray background), I had to create an /etc/terminal-colors.d directory and then create an empty disable file inside it. You cannot make this stuff up. – mosvy Nov 1 '19 at 22:23
3
+100

If I understand the question correctly, it really boils down to opinion? The following tries to summarize some points worth considering

Not all output is to terminals

As trivial as it sounds, even if every terminal on the world understands the ANSI sequences correctly (it is not the case as mentioned in the comments, for statements about all it is sufficient to find one counterexample to reject the statement): Consider the two cases of redirection to files or pipelining the output trough other programs (e.g. an interactively used grep or scripted invication of the programs).

In these cases, it is often desirable to be able to obtain an output which is not colorized to simplify processing. Relying entirely on the environment's TERM variable can still be insufficient in these cases e.g. a pipeline may be entered interactively which will cause TERM to be set but color output to be (potentially) undesirable.

Colors can be different

I have written quite a few scripts which just output raw ANSI sequences independently of TERM (usually with an option to turn that coloring on/off). Using different terminal emulators, shells or even options for the same terminal emulator, I have often received differently colored output. Rarely (but the cases exist and can all be found on modern Linux systems) I have also noticed that the coloring goes beyond recognition (e.g. dark gray on black or such). At times, something that ought to be colored just green had also been applied a "crossed out" effect on it...

For the "fun insight", take any test that uses a lot of ANSI escape sequences unconditionally (i.e. independently of TERM) and then run it in: rxvt, gnome-terminal, xterm and finally on the Linux Console.

Without employing one of the abstraction layers, there are always chances that the colorization will fail although the escape sequences are recognized and processed by the target application.

Conclusion

In 2019 it is not exactly safe to assume that raw ANSI escape sequences will work as expected.

Consider how important terminal control is to your application: If it is important (in the sense, that it loses significant functionality without colors/terminal control), the risk for having something go wrong with raw ANSI escape sequences is just too high. If it is not so important (e.g. eye-candy for logs, fancy interactive menus vs. simple interactive menus etc), it seems reasonable to go with a very limited abstraction of colored output (e.g. raw ANSI sequences + option to turn of all colors).

Other relativizing statements

When the same application that requires colored output or other terminal control sequences also needs to obtain input in a special way, then it is time to go for a thoroughly developed solution like ncurses or something more "modern"...

As has been noted in the comments: Only the tested environments are really safe for any software. In case you know the environment, it is always possible (although at the cost of some abstract "portability") to add assumptions to your program that are fulfilled in that environment.

Finally, programs which are actually using a more advanced library with terminal information are not safe under all circumstances either: Colors vary with configured terminal color schemes and some effects like underline are just not available with all terminal and font combinations. Then, there are also some cases when TERM is being set "incorrectly" causing an application to fail (I frequently experience problems when running a tmux over ssh).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.