Script Tip: Modifying text appearance in console output
March 29, 2016
When writing user-facing scripts you sometimes want to emphasize a word or a line in the text printed to the console to make it easier to read (or harder to miss).
Common use cases include changing the text color or setting attributes like bold or underlined.
This is made possible through the ISO/IEC 6429 SGR (Select Graphic Rendition) escape sequences (1) (commonly referred to as the ANSI escape codes).
When an SGR escape sequence is sent, the terminal application interprets the code and modifies the appearance of all subsequent characters printed to match the command until a new escape sequence is sent that either updates or clears the current modifications.
tput
There are many different terminal control languages. Browse the following directory to see all language files (terminfo) recognized by your system:
/usr/share/terminfo
Because of the lack of standardization there was a need to create a tool that could translate what you intended the terminal to display to the correct escape code for the current terminal.
tput handles that translation for most of the escape sequences needed in a portable way.
This is the recommended way of passing escape sequences to the terminal (instead of hardcoding the values for a specific terminal type).
My setup
In BASH, I use a function to set up variables for the escape sequences I’m going to use. Then I use the variable name (instead of the tput command or hardcoded escape sequence) directly inline with the text I want to output.
By referencing the escape sequences by their variable names, it’s easier to understand what will be printed to the screen, but also easier (and faster) to write correct code.
Here is a link to my reference function containing the variables I often use: SGR variables
Color (Foreground)
When adding this to a script, I create a new function and add the ones I am going to use instead of copying and pasting all escape sequences (to avoid unused variables).
This function is setting up the variables for the foreground color escape sequences I’ll need:
sgr_variables() {
# Foreground text colors
red=$(tput setaf 1) # Red
grn=$(tput setaf 2) # Green
blu=$(tput setaf 4) # Blue
def=$'\e[39m' # Default foreground color
# Deactivate ALL sgr attributes and colors.
clr=$(tput sgr0)
}
The variables can then be used inline with the text to be printed:
# Call the function ONCE to set up the variables before using them.
sgr_variables
printf "%s\n" "${red}Red${def},${grn}Green${def},${blu}Blue${clr}"
Color (Background)
Using the example from above, but this time change the text background color instead:
I have updated the sgr_variables function to include the new variables from my referece.
# Call the function ONCE to set up the variables before using them.
sgr_variables
printf "%s\n" "${bgred}Red${bgdef},${bggrn}Green${bgdef},${bgblu}Blue${clr}"
Attributes
The following attributes can also be sent as escape sequences to modify text appearance:
- Bold
- Dim
- Underscore
- Blink
- Reverse (Swap foreground and background color)
- Hidden
Using the first example, but also adding some text attributes:
- Add Bold to Red
- Add Dim to Green (bold is still active)
- Remove Bold and Dim by using ${nobld}
- Add Underline to Blue
I have updated the sgr_variables function to include the new variables from my referece.
# Call the function ONCE to set up the variables before using them.
sgr_variables
printf "%s\n" \
"${red}${bld}Red${def},${grn}${dim}Green${nobld}${def},${blu}${uln}Blue${clr}"
Example Use Case
Colorized Status
This is an example that will print three status messages in different colors:
printf "%-15s\t%s\n" "StatusOk:" "[${grn}${bld}OK${clr}]"
printf "%-15s\t%s\n" "StatusWarn:" "[${yel}${bld}WARN${clr}]"
printf "%-15s\t%s\n" "StatusError:" "[${red}${bld}ERROR${clr}]"
Final Notes
The escape sequence variables are not tied to printf, they can just as easily be used with echo:
# Call the function ONCE to set up the variables before using them.
sgr_variables
echo "${red}Red${def},${grn}Green${def},${blu}Blue${clr}"
To print your current terminal type, use this command:
echo $TERM
To print your current terminal terminfo file, use this command:
infocmp -L -1
-
Section 8.3.117 of the Standard ECMA-48 (Control Functions for Coded Character Sets) ↩