Read the current text color in a xterm
Asked Answered
A

4

35

I'm writing various utilities, and I'm really liking colorized text. Nothing fancy, just using escape sequences. I've created a simple class that has a pprint(msg, color) function. I've got it working rather easily after finding the codes here.

The problem that I'm having is that I should be able to turn off the color after printing. For example, let's say a user runs my program that prints almost everything in the default terminal color, but there is an error, and I want to print the error in red. I prefix my error message with '\033[0;32m', and the message is in red. Unfortunately, all text is red until I change it. That's generally fine while my program is running because I know what color the messages should be. However, the color remains after my program ends. Basically, I'd like to read the current color when my program starts, and restore it when finished. The same way that scripts restore the pwd when exiting.

How do I read the current escape sequence?

System: Red Hat 5.x Bash Python 2.3

Thanks for the help.

Alembic answered 2/12, 2010 at 6:59 Comment(0)
N
4

I don't believe that's possible and it's unlikely to be portable if it were. The best you can do is send sgr0 which resets all attributes to default (not previous). On xterms, sgr0 is Esc[m. If you want to reset the colors and not affect other attributes, send op which on xterms is Esc[39;49m.

These codes should not be hardcoded. You should use terminfo, termcap or [n]curses.

Nial answered 2/12, 2010 at 11:48 Comment(2)
Thanks for the response. I looked over the link that you provided, but couldn't find anything relevant to sgr0 or colors. Could you elaborate or provide the section? Reseting sgr0 seems to work perfectly, and unless there's a compelling portability reason, I'll stick with it in the short-term. Using something that interface with terminfo/termcap or curses directly will be the plan going forward, but it's going to take a while to get those modules added.Alembic
@fandingo: The point of the link is that many terminal emulators that claim to be xterm compatible don't support many of the control sequences that xterm does, thus affecting portability of more obscure capabilities. You can find out more about terminfo in man 5 terminfo and xterm control sequences here.Nial
D
162

Rather than using obfuscated escape sequences, use the tput facility instead. Here is an excerpt from my ~/.bashrc that I use for my PS1 prompt:

BLACK=$(tput setaf 0)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
LIME_YELLOW=$(tput setaf 190)
POWDER_BLUE=$(tput setaf 153)
BLUE=$(tput setaf 4)
MAGENTA=$(tput setaf 5)
CYAN=$(tput setaf 6)
WHITE=$(tput setaf 7)
BRIGHT=$(tput bold)
NORMAL=$(tput sgr0)
BLINK=$(tput blink)
REVERSE=$(tput smso)
UNDERLINE=$(tput smul)

To reset the color information such that subsequent text is in the normal terminal color you would append ${NORMAL} to the end like so:

echo "${RED}this is red ${NORMAL}this is normal"

Dixil answered 2/12, 2010 at 7:7 Comment(7)
Useful, but doesn't answer the question as I read it. The user didn't necessarily have the terminal set to the "normal" colour before running the script, and might not want the script to set the "normal" colour afterward.Pouncey
Thanks for the answer, but Karl is correct. I need to set it within Python scripts, so while BASH aliases would work, they don't seem to be the best solution. Not that escape sequences are much better...Alembic
Another dependency.. the last thing I need.Uptrend
@Dan was that directed at my answer? If so tput comes with ncurses, so although it's not a bash built-in, it's pretty much ubiquitous.Dixil
It's not ubiquitous on Windows. I use .sh scripts in combination with Git Bash and there are many useful Linux tools that I don't have at my convenience. tput is one of them. Sure, I could run cygwin or even just drop a tput executable in my Git directory, but this seems like overkill when the escape sequences work perfectly well. TBH, $(tput setaf 6) isn't any less obfuscated than '\e[00;36m' to me. They also don't fork another process 15 times while initializing the color constants.Uptrend
@Dan we'll you can't please all of the people all the time, 1 out of 18 is pretty good.Dixil
@Dixil I wasn't your downvote FYI. I appreciate your answer for what it is, these are just my observations. I was frustrated with some other hacky solutions at the time of my initial comment, sorry for that.Uptrend
C
6

Actually, it's possible — for xterm, and compatible terminals.

xtermcontrol for instance uses the OSC 10 control sequence to retrieve the default foreground/background colors. It's been documented in xterm since 2002.

For other terminals:

  • In RHEL 5, the "Terminal" program is gnome-terminal 2.16.0; that version does not recognize OSC 10 (tested with the equivalent CentOS 5).
  • The question was asked in 2010, referring to the Red Hat enterprise version, which, if anything, is slower to update than Debian.
  • Moving forward in time, gnome-terminal 3.4.1.1 on Debian 7 (early 2012) also did not recognize the control sequence.
  • Finally, in Debian 8 with 3.14.1 (late 2014) the feature is recognized.
  • CentOS 7's gnome-terminal 3.14.3 recognizes the control sequence.

Curious when it was added, bear in mind that VTE's developers don't write documentation. So... studying the git log shows

commit 1b8c6b1aac587b79476a60a5830385abc939430d 
Author: Egmont Koblinger <[email protected]> 
Date:   Wed Jan 22 00:13:51 2014 +0100

    emulation: Add support for OSC 1?1[017] (fg, bg, highlight colors)

    https://bugzilla.gnome.org/show_bug.cgi?id=567444

On the other hand, the default colors are not the same as the current colors. Users have been able to do this with xterm since patch #93 in 1999 using the DECRQSS control sequence. That is, putting the terminal into raw mode and doing something like

printf '\033P$m\033\\'

would get it to reply with the string filled out with the SGR parameters.

If colors were set using SGR, those codes would be part of the reply, e.g.

\033P1$r0;33m\033\\

to denote foreground color number 3 (encoded as 33).

You could stop there (because you could extract those parameters and reuse them to set the terminal to the same state later), but then getting the actual RGB colors would be possible using OSC 4. You'd use the color number (from the SGR sequence), and send something like this:

printf '\033]4;3;?\033\\'

So it's certainly doable with xterm. There'll be a demo/test-script for DECRQSS in the next update for xterm.

For other programs, you need more time:

  • xtermcontrol's developer overlooked DECRQSS (it has no feature for setting/getting SGR codes).

  • VTE's developers copy xterm features in response to bug reports; the VTE source does not mention DECRQSS. Its git log mentions OSC 4 in 2009, but the implementation is incomplete (it only allows one to set a color, not get the color).

Carbonaceous answered 22/1, 2017 at 19:59 Comment(0)
T
4
RED = 31
GREEN = 32
ESCAPE = '%s[' % chr(27)
RESET = '%s0m' % ESCAPE
FORMAT = '1;%dm'

def colorize(text, color):
    return ESCAPE + (FORMAT % (color, )) + text + RESET

This function will return a string that will print colorized, with the terminal automatically being reset afterwards.

Theresa answered 2/12, 2010 at 7:15 Comment(1)
There is a problem with the escape sequences. When I print with it, I see the text and all the escape sequences.Alembic
N
4

I don't believe that's possible and it's unlikely to be portable if it were. The best you can do is send sgr0 which resets all attributes to default (not previous). On xterms, sgr0 is Esc[m. If you want to reset the colors and not affect other attributes, send op which on xterms is Esc[39;49m.

These codes should not be hardcoded. You should use terminfo, termcap or [n]curses.

Nial answered 2/12, 2010 at 11:48 Comment(2)
Thanks for the response. I looked over the link that you provided, but couldn't find anything relevant to sgr0 or colors. Could you elaborate or provide the section? Reseting sgr0 seems to work perfectly, and unless there's a compelling portability reason, I'll stick with it in the short-term. Using something that interface with terminfo/termcap or curses directly will be the plan going forward, but it's going to take a while to get those modules added.Alembic
@fandingo: The point of the link is that many terminal emulators that claim to be xterm compatible don't support many of the control sequences that xterm does, thus affecting portability of more obscure capabilities. You can find out more about terminfo in man 5 terminfo and xterm control sequences here.Nial

© 2022 - 2024 — McMap. All rights reserved.