Styling terminal output

Many terminal applications and linux utilities have support for colored output, made possible by ANSI escape sequences. There are sequences for many different terminal controls like moving cursors, setting titles and styling content. For brevity we only cover the text styling related ones, refer to the ECMA-48 standard if you need more than colors and text formatting.

Understanding ANSI escape sequences

Since terminals have no direct API a program could call, they instead rely on specifically formatted output to change terminal appearance or behavior. These were initially standardized by ANSI X3.64 and begin with an the ASCII ESC character, followed by a sequence of characters that the terminal interprets as a command - hence the name "ANSI escape sequence". Although the current standards ECMA-48 / ISO/IEC 6429 have long superseded ANSI X3.64, "ANSI escape sequence" remains the commonly used name.


The ESC characters can be output by most programs either in hexadecimal form \x1b or octal notation as \033. Some languages like bash also support the syntax \e to produce it, but most do not.


Escape sequences are structured like this:

\033[1;30m

The [ following the ESC character selects the command family. For terminal styling you will need CSI (Control Sequence Introducer) group, which uses [. Following it is a list of one or more numeric codes delimited by semicolons ;. The last character is called the final byte, which selects the mode the operation should use. Text styling will always use SGR (Select Graphic Rendition), using the letter m.


The codes within an escape sequence are applied from left to right, and conflicting ones will override the previous one. An escape sequence applies rules like text formatting or color until it is reset, either by a complete reset (0) or a selective one (22-29).

Core ANSI styles

These are the official codes defined by the ECMA-48 standard. While most terminals claim compatibility with this standard, they often omit some codes or implement their behavior differently.


Text control:

  • 1 - High intensity text. Most terminals render this text bold, some as bright color instead

  • 2 - Faint/dimmed text, unreliable support

  • 3 - Italic. Often missing in old or simple terminals

  • 4 - Underline

  • 5 - Blink. Rarely supported

  • 6 - Rapid blink. Rarely supported

  • 7 - Reverse video. Reverses foreground and background color, useful to highlight/mark text

  • 8 - Conceal text. Renders text as whitespace, largely useless today. Prefer disabling echo instead

  • 9 - Strikethrough. Crossed out text, unreliable support across terminals

  • 0 - Complete reset. Disables all previous styles

  • 22 - Disable bold/faint

  • 23 - Disable italic

  • 24 - Disable underline

  • 25 - Disable blink

  • 27 - Disable reverse video

  • 28 - Disable text concealment

  • 29 - Disable strikethrough


Foreground colors:

  • 30 - Black foreground

  • 31 - Red foreground

  • 32 - Green foreground

  • 33 - Yellow foreground

  • 34 - Blue foreground

  • 35 - Magenta foreground

  • 36 - Cyan foreground

  • 37 - White foreground


Background colors:

  • 41 - Red background

  • 42 - Green background

  • 43 - Yellow background

  • 44 - Blue background

  • 45 - Magenta background

  • 46 - Cyan background

  • 47 - White background

You can check what core colors look like visually in your terminal with

for code in {30..37} {40..47}; \
  do printf "\033[${code}m%3s\033[0m\n" "$code"; done

Do not rely on these colors too heavily, as they may not behave the same across terminals. Most terminals allow users to set their own theme with custom color codes, so nothing stops them from turning text yellow when the "green" escape sequence is used.

Even without user customizations, color shades visually differ between terminal implementations.

Bright colors

Technically an extension to the ECMA-48 standard, the bright colors are well-supported across most terminals and provide better visual clarity for terminal output:


Bright foreground colors:

  • 90 - Bright black foreground (often gray)

  • 91 - Bright red foreground (often orange)

  • 92 - Bright green foreground

  • 93 - Bright yellow foreground

  • 94 - Bright blue foreground

  • 95 - Bright magenta foreground

  • 96 - Bright cyan foreground

  • 97 - Bright white foreground


Bright background colors:

  • 100 - Bright black background

  • 101 - Bright red background

  • 102 - Bright green background

  • 103 - Bright yellow background

  • 104 - Bright blue background

  • 105 - Bright magenta background

  • 106 - Bright cyan background

  • 107 - Bright white background

You can check what bright colors look like visually in your terminal with


You can check what bright colors look like visually in your terminal with

for code in {90..97} {100..107}; \
  do printf "\033[${code}m%3s\033[0m\n" "$code"; done

Remember that the "bold/high intensity" escape sequence may also render text as bright colors instead, which may lead to confusion.

As with the original 8 colors, the terminal theme may be altered to redefine what color is printed when selecting any escape sequence, so do not rely too heavily on these escape sequences to produce a specific color. Exact color shades also vary between terminal implementations.

xTerm extension

The xterm extensions brought more color support, first through 256 addon colors, then later full true color support from 24-bit RGB values. For modern terminals, you should always prefer RGB since terminals implementing one will almost certainly support both anyway, and RGB yields more control.


Note that the xterm extension is supported by most modern terminals, but simpler implementations like /dev/tty or virtual login terminals often don't implement them.


24bit RGB colors

  • 38;2;R;G;Bm sets foreground color to RGB color. Replace R, G and B with real 24bit RGB values

  • 48;2;R;G;Bm sets background color to RGB color. Replace R, G and B with real 24bit RGB values

Unlike the 8/16 core colors, true color RGB values are not affected by terminal themes and do not vary visually between terminal implementations. While this may sound desirable, they are somewhat frowned upon as they may not work well with custom terminal themes, and users that spent time customizing their terminal appearance tend to get fairly upset when a program doesn't respect their choices.

Also note that accessibility is fully in your hands when using true color shades, since terminal high contrast or better readability settings will be ignored as well.


The xterm extension also contains other styling options to create clickable hyperlinks and set the terminal title, but we omit them here since they are less commonly used.

Robust terminal styling guidelines

There are some simple rules you can follow to avoid common issues with styled terminal output.


Make styling optional. Escape sequences only work inside terminals, so something as simple as a pipe | or redirecting output to a file will turn the output into a mess of real output and raw escape sequences. Most linux tools turn colors off by default and allow users to turn them on with the --color=on/auto flag if they want. If you want to have color by default, at least respect the NO_COLOR environment variable.


Always check if stdout is a terminal. Most users will want colored output on the terminal, but no escape sequences for other output targets. Providing an "auto" which uses language builtins like C's isatty to check if stdout is a terminal and enabling colors if true is what most users expect today. Do not rely on environment variables like TERM alone as they may be incorrect.


Prefer the core 8/16 colors. They respect custom theme colors, which may be vital for users that rely on accessibility themes for high contrast or visual impairments. RGB true color seems like a nice standardized option to get just the color you wanted, but it is rarely the better choice in the real world.


Do not encode meaning in color alone. You might be tempted to distinguish warnings from errors by using different colors, but this breaks when output is redirected to a log file or is piped into a viewer like less. Always ensure that the output text contains all the necessary information and context, and use color as a helper to quickly scan or segment output in environments that support it.


Do not rely on specific colors. As terminal themes can alter non-RGB color values, do not rely on the color alone in documentation or guides. If you refer to "the green portion of the output", at least provide a screenshot so users with different color schemes can see what you are talking about.

More articles

The complete guide to C strings

Including common problems and solutions

Working with disk image files in linux

From loop devices to mounting

Reducing internal tool sprawl with homarr

Replace scattered links with a role-aware web launcher