Differences between revisions 1 and 25 (spanning 24 versions)
Revision 1 as of 2007-05-02 23:26:33
Size: 775
Editor: redondos
Comment:
Revision 25 as of 2012-10-25 17:54:48
Size: 9005
Editor: Lhunath
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
[[Anchor(faq37)]] <<Anchor(faq37)>>
Line 3: Line 3:
''Do not'' hard-code ANSI color escape sequences in your program! The {{{tput}}} command lets you interact with the terminal database in a sane way. ''Do not'' hard-code ANSI color escape sequences in your program! The {{{tput}}} command lets you interact with the terminal database in a sane way:
Line 6: Line 6:
  # Bourne
Line 8: Line 9:
  tput setaf 0; echo now we are back in black   tput bold; echo "boldface (and still green)"
  tput sgr0; echo back to normal
Line 10: Line 12:

'''Cygwin users:''' you need to install the `ncurses` package to get `tput` (see: [[http://old.nabble.com/Where-did-%22tput%22-go-in-1.7--ts22422087.html|Where did "tput" go in 1.7?]])
Line 13: Line 17:
If you don't know in advance what your user's terminal's default text color is, you can use {{{tput sgr0}}} to reset the colors to their default settings. This also removes boldface ({{{tput bold}}}), etc. {{{tput sgr0}}} resets the colors to their default settings. This also turns off boldface ({{{tput bold}}}), underline, etc.

If you want fancy colors in your prompt, consider using something manageable:

{{{
  # Bash
  red=$(tput setaf 1)
  green=$(tput setaf 2)
  blue=$(tput setaf 4)
  reset=$(tput sgr0)
  PS1='\[$red\]\u\[$reset\]@\[$green\]\h\[$reset\]:\[$blue\]\w\[$reset\]\$ '
}}}

Note that we do '''not''' hard-code ANSI color escape sequences. Instead, we [[BashFAQ/002|store the output]] of the `tput` command into variables, which are then used when `$PS1` is expanded. Storing the values means we don't have to fork a `tput` process multiple times every time the prompt is displayed; `tput` is only invoked 4 times during [[DotFiles|shell startup]]. The `\[` and `\]` symbols allow bash to understand which parts of the prompt cause no cursor movement; without them, [[BashFAQ/053|lines will wrap incorrectly]].

See also [[http://wiki.bash-hackers.org/scripting/terminalcodes]] for an overview.

The following is a more extensive range of terminal sequence variables. Pick the ones you want:

{{{
# Variables for terminal requests.
[[ -t 2 ]] && {
    alt=$( tput smcup || tput ti ) # Start alt display
    ealt=$( tput rmcup || tput te ) # End alt display
    hide=$( tput civis || tput vi ) # Hide cursor
    show=$( tput cnorm || tput ve ) # Show cursor
    save=$( tput sc ) # Save cursor
    load=$( tput rc ) # Load cursor
    bold=$( tput bold || tput md ) # Start bold
    stout=$( tput smso || tput so ) # Start stand-out
    estout=$( tput rmso || tput se ) # End stand-out
    under=$( tput smul || tput us ) # Start underline
    eunder=$( tput rmul || tput ue ) # End underline
    reset=$( tput sgr0 || tput me ) # Reset cursor
    blink=$( tput blink || tput mb ) # Start blinking
    italic=$( tput sitm || tput ZH ) # Start italic
    eitalic=$( tput ritm || tput ZR ) # End italic
[[ $TERM != *-m ]] && {
    red=$( tput setaf 1|| tput AF 1 )
    green=$( tput setaf 2|| tput AF 2 )
    yellow=$( tput setaf 3|| tput AF 3 )
    blue=$( tput setaf 4|| tput AF 4 )
    magenta=$( tput setaf 5|| tput AF 5 )
    cyan=$( tput setaf 6|| tput AF 6 )
}
    white=$( tput setaf 7|| tput AF 7 )
    default=$( tput op )
    eed=$( tput ed || tput cd ) # Erase to end of display
    eel=$( tput el || tput ce ) # Erase to end of line
    ebl=$( tput el1 || tput cb ) # Erase to beginning of line
    ewl=$eel$ebl # Erase whole line
    draw=$( tput -S <<< ' enacs
                                smacs
                                acsc
                                rmacs' || { \
                tput eA; tput as;
                tput ac; tput ae; } ) # Drawing characters
    back=$'\b'
} 2>/dev/null ||:
}}}

The above leaves the variables unset when stderr isn't connected to a terminal and leaves the color variables unset for monochrome terminals. The alternative `tput` executions allow the code to keep working on systems where `tput` takes old termcap names instead ANSI capnames. It also uses `2>/dev/null ||:` to silence potential errors and avoid `ERR` script abortion. That allows this code to be used in a range of edge cases such as scripts that use set -e and terminals or OS's that don't support certain sequences (the code is borrowed from http://to.lhunath.com/bashlib).

=== Discussion ===

This will be contentious, but I'm going to disagree and recommend you use hard-coded ANSI escape sequences because terminfo databases in the real world are too often broken.

tput setaf literally means "Set ANSI foreground" and shouldn't have any difference with a hard-coded ANSI escape sequence, except that it will actually work with broken terminfo databases so your colors will look correct in a VT with terminal type linux-16color or any terminal type so long as it really is a terminal capable of 16 ANSI colors.

So ''do'' consider setting those variables to hard-coded ANSI sequences such as:

{{{
  # Bash
  white=$'\e[0;37m'
}}}

  ''You assume the entire world of terminals that you will ever use always conforms to one single set of escape sequences. This is a very poor assumption. Maybe I'm showing my age, but in my first job after college, in 1993-1994, I worked with a wide variety of physical terminals (IBM 3151, Wyse 30, NCR something or other, etc.) all in the same work place. They all had different key mappings, different escape sequences, the works. If I were to hard-code a terminal escape sequence as you propose it would only work on ONE of those terminals, and then if I had to login from someone else's office, or from a server console, I'd be screwed. So, for personal use, if this makes you happy, I can't stop you. But the notion of writing a script that uses hard-coded escape sequences and then DISTRIBUTING that for other people should be discarded immediately.'' - GreyCat <<BR>><<BR>>

      I said it would be contentious, but there is an alternative view. A large number of people today will use Linux on their servers and their desktops and their profiles follow them around. The terminfo for linux-16color is broken. By doing it the "right" way, they will find their colors do not work correctly in a virtual terminal on one of the console tty's. Doing it the "wrong" way will result only in light red becoming bold if they use the real xterm or a close derivitve. If terminfo can't get it right for something as common as linux-16color, it's hard to recommend relying on it. People should be aware that it doesn't work correctly, try it yourself, go through the first 16 colours on A Linux VT with linux-16color. I know ANSI only specified names not hue's but setaf 7 is obviously not supposed to result in black text seeing as it is named white. I'd place money on a lot more people using Linux for their servers than any other UNIX based OS and if they are using another UNIX-based or true UNIX they are probably aware of the nuances. A Linux newbie would be very surprised to find after following the "right way" her colors did not work properly on a VT. Of course the correct thing to do is to fix terminfo, but that isn't in my power, although I have reported the bug for linux-16color in particular, how many other bugs are there in it? The only completely accurate thing to do is to hard-code the sequences for all the terminals you will encounter yourself, which is what terminfo is supposed to avoid the necessity of doing. However, it is buggy in at least this case (and a very common case), so relying on it to do it properly is also suspect. I will add here I have much respect for Greycat, and he is a very knowledgeable expert in many areas of IT; I fully admit I do not have the same depth of knowledge as he does, but will YOU ever be working on a Wyse 30? '''''To be completely clear, I'm suggesting that you should consider hard-coded colors for your own profile and uses, if you are intending to write a completely portable script for others to use on foreign systems then you should rely on terminfo/termcap even if it is buggy.'''''

  . I've never heard of linux-16colors before. It's not an installed terminfo entry in Debian, at least not by default. If your vendor is shipping broken terminfo databases, file a bug report. Meanwhile, find a system where the entry you need is not broken, and copy it to your broken system(s) -- or write it yourself. That's what the rest of the world has always done. It's where the terminfo entries came from in the first place. Someone had to write them all.
  . {{http://wooledge.org/~greg/linux-console-colors.png}}
  . -- GreyCat

----
CategoryShell

How can I print text in various colors?

Do not hard-code ANSI color escape sequences in your program! The tput command lets you interact with the terminal database in a sane way:

  # Bourne
  tput setaf 1; echo this is red
  tput setaf 2; echo this is green
  tput bold; echo "boldface (and still green)"
  tput sgr0; echo back to normal

Cygwin users: you need to install the ncurses package to get tput (see: Where did "tput" go in 1.7?)

tput reads the terminfo database which contains all the escape codes necessary for interacting with your terminal, as defined by the $TERM variable. For more details, see the terminfo(5) man page.

tput sgr0 resets the colors to their default settings. This also turns off boldface (tput bold), underline, etc.

If you want fancy colors in your prompt, consider using something manageable:

  # Bash
  red=$(tput setaf 1)
  green=$(tput setaf 2)
  blue=$(tput setaf 4)
  reset=$(tput sgr0)
  PS1='\[$red\]\u\[$reset\]@\[$green\]\h\[$reset\]:\[$blue\]\w\[$reset\]\$ '

Note that we do not hard-code ANSI color escape sequences. Instead, we store the output of the tput command into variables, which are then used when $PS1 is expanded. Storing the values means we don't have to fork a tput process multiple times every time the prompt is displayed; tput is only invoked 4 times during shell startup. The \[ and \] symbols allow bash to understand which parts of the prompt cause no cursor movement; without them, lines will wrap incorrectly.

See also http://wiki.bash-hackers.org/scripting/terminalcodes for an overview.

The following is a more extensive range of terminal sequence variables. Pick the ones you want:

# Variables for terminal requests.
[[ -t 2 ]] && { 
    alt=$(      tput smcup  || tput ti      ) # Start alt display
    ealt=$(     tput rmcup  || tput te      ) # End   alt display
    hide=$(     tput civis  || tput vi      ) # Hide cursor
    show=$(     tput cnorm  || tput ve      ) # Show cursor
    save=$(     tput sc                     ) # Save cursor
    load=$(     tput rc                     ) # Load cursor
    bold=$(     tput bold   || tput md      ) # Start bold
    stout=$(    tput smso   || tput so      ) # Start stand-out
    estout=$(   tput rmso   || tput se      ) # End stand-out
    under=$(    tput smul   || tput us      ) # Start underline
    eunder=$(   tput rmul   || tput ue      ) # End   underline
    reset=$(    tput sgr0   || tput me      ) # Reset cursor
    blink=$(    tput blink  || tput mb      ) # Start blinking
    italic=$(   tput sitm   || tput ZH      ) # Start italic
    eitalic=$(  tput ritm   || tput ZR      ) # End   italic
[[ $TERM != *-m ]] && { 
    red=$(      tput setaf 1|| tput AF 1    )
    green=$(    tput setaf 2|| tput AF 2    )
    yellow=$(   tput setaf 3|| tput AF 3    )
    blue=$(     tput setaf 4|| tput AF 4    )
    magenta=$(  tput setaf 5|| tput AF 5    )
    cyan=$(     tput setaf 6|| tput AF 6    )
}
    white=$(    tput setaf 7|| tput AF 7    )
    default=$(  tput op                     )                                                                                                                                                                   
    eed=$(      tput ed     || tput cd      )   # Erase to end of display
    eel=$(      tput el     || tput ce      )   # Erase to end of line
    ebl=$(      tput el1    || tput cb      )   # Erase to beginning of line
    ewl=$eel$ebl                                # Erase whole line
    draw=$(     tput -S <<< '   enacs
                                smacs
                                acsc
                                rmacs' || { \
                tput eA; tput as;
                tput ac; tput ae;         } )   # Drawing characters
    back=$'\b'
} 2>/dev/null ||:

The above leaves the variables unset when stderr isn't connected to a terminal and leaves the color variables unset for monochrome terminals. The alternative tput executions allow the code to keep working on systems where tput takes old termcap names instead ANSI capnames. It also uses 2>/dev/null ||: to silence potential errors and avoid ERR script abortion. That allows this code to be used in a range of edge cases such as scripts that use set -e and terminals or OS's that don't support certain sequences (the code is borrowed from http://to.lhunath.com/bashlib).

Discussion

This will be contentious, but I'm going to disagree and recommend you use hard-coded ANSI escape sequences because terminfo databases in the real world are too often broken.

tput setaf literally means "Set ANSI foreground" and shouldn't have any difference with a hard-coded ANSI escape sequence, except that it will actually work with broken terminfo databases so your colors will look correct in a VT with terminal type linux-16color or any terminal type so long as it really is a terminal capable of 16 ANSI colors.

So do consider setting those variables to hard-coded ANSI sequences such as:

  # Bash
  white=$'\e[0;37m'
  • You assume the entire world of terminals that you will ever use always conforms to one single set of escape sequences. This is a very poor assumption. Maybe I'm showing my age, but in my first job after college, in 1993-1994, I worked with a wide variety of physical terminals (IBM 3151, Wyse 30, NCR something or other, etc.) all in the same work place. They all had different key mappings, different escape sequences, the works. If I were to hard-code a terminal escape sequence as you propose it would only work on ONE of those terminals, and then if I had to login from someone else's office, or from a server console, I'd be screwed. So, for personal use, if this makes you happy, I can't stop you. But the notion of writing a script that uses hard-coded escape sequences and then DISTRIBUTING that for other people should be discarded immediately. - GreyCat

    • I said it would be contentious, but there is an alternative view. A large number of people today will use Linux on their servers and their desktops and their profiles follow them around. The terminfo for linux-16color is broken. By doing it the "right" way, they will find their colors do not work correctly in a virtual terminal on one of the console tty's. Doing it the "wrong" way will result only in light red becoming bold if they use the real xterm or a close derivitve. If terminfo can't get it right for something as common as linux-16color, it's hard to recommend relying on it. People should be aware that it doesn't work correctly, try it yourself, go through the first 16 colours on A Linux VT with linux-16color. I know ANSI only specified names not hue's but setaf 7 is obviously not supposed to result in black text seeing as it is named white. I'd place money on a lot more people using Linux for their servers than any other UNIX based OS and if they are using another UNIX-based or true UNIX they are probably aware of the nuances. A Linux newbie would be very surprised to find after following the "right way" her colors did not work properly on a VT. Of course the correct thing to do is to fix terminfo, but that isn't in my power, although I have reported the bug for linux-16color in particular, how many other bugs are there in it? The only completely accurate thing to do is to hard-code the sequences for all the terminals you will encounter yourself, which is what terminfo is supposed to avoid the necessity of doing. However, it is buggy in at least this case (and a very common case), so relying on it to do it properly is also suspect. I will add here I have much respect for Greycat, and he is a very knowledgeable expert in many areas of IT; I fully admit I do not have the same depth of knowledge as he does, but will YOU ever be working on a Wyse 30? To be completely clear, I'm suggesting that you should consider hard-coded colors for your own profile and uses, if you are intending to write a completely portable script for others to use on foreign systems then you should rely on terminfo/termcap even if it is buggy.

  • I've never heard of linux-16colors before. It's not an installed terminfo entry in Debian, at least not by default. If your vendor is shipping broken terminfo databases, file a bug report. Meanwhile, find a system where the entry you need is not broken, and copy it to your broken system(s) -- or write it yourself. That's what the rest of the world has always done. It's where the terminfo entries came from in the first place. Someone had to write them all.
  • http://wooledge.org/~greg/linux-console-colors.png

  • -- GreyCat


CategoryShell

BashFAQ/037 (last edited 2023-10-01 21:59:10 by larryv)