ANSI Escape Sequences
ANSI escape sequences for colors, formatting, and cursor control.
CSI (Control Sequence Introducer)
All ANSI sequences begin with ESC[ (the Control Sequence Introducer).
| Notation | Description | Portability |
|---|---|---|
|
Octal |
Most portable (POSIX) |
|
Hexadecimal |
Widely supported |
|
Bash shorthand |
Bash only (not POSIX) |
# All three produce the same result
printf "\033[1mBold\033[0m\n" # Octal - use this
printf "\x1b[1mBold\x1b[0m\n" # Hex
printf "\e[1mBold\e[0m\n" # Bash only
Basic Colors (8-color mode)
| Foreground | Code | Background | Code |
|---|---|---|---|
Black |
30 |
Black BG |
40 |
Red |
31 |
Red BG |
41 |
Green |
32 |
Green BG |
42 |
Yellow |
33 |
Yellow BG |
43 |
Blue |
34 |
Blue BG |
44 |
Magenta |
35 |
Magenta BG |
45 |
Cyan |
36 |
Cyan BG |
46 |
White |
37 |
White BG |
47 |
echo -e "\033[31mRed text\033[0m"
echo -e "\033[32mGreen text\033[0m"
echo -e "\033[33;44mYellow on Blue\033[0m"
Bright variants: Add 60 (foreground 90-97, background 100-107):
echo -e "\033[91mBright Red\033[0m"
echo -e "\033[92mBright Green\033[0m"
256 Color Mode
# Foreground: \033[38;5;Nm (N = 0-255)
# Background: \033[48;5;Nm
echo -e "\033[38;5;208mOrange (208)\033[0m"
echo -e "\033[38;5;39mSky Blue (39)\033[0m"
echo -e "\033[48;5;236;38;5;231mWhite on Dark Gray\033[0m"
# Show all 256 colors
for i in {0..255}; do
printf "\033[38;5;${i}m%3d\033[0m " "$i"
[[ $((i % 16)) -eq 15 ]] && echo
done
True Color (24-bit RGB)
# Foreground: \033[38;2;R;G;Bm
# Background: \033[48;2;R;G;Bm
echo -e "\033[38;2;255;128;0mTrue Orange\033[0m"
echo -e "\033[38;2;128;0;255mTrue Purple\033[0m"
# Gradient
for i in {0..255..5}; do
printf "\033[48;2;%d;0;%dm \033[0m" "$i" "$((255-i))"
done
echo
Text Formatting (SGR Codes)
| Code | Effect | Reset Code |
|---|---|---|
0 |
Reset all |
- |
1 |
Bold |
22 |
2 |
Dim/Faint |
22 |
3 |
Italic |
23 |
4 |
Underline |
24 |
5 |
Blink |
25 |
7 |
Reverse/Inverse |
27 |
8 |
Hidden |
28 |
9 |
Strikethrough |
29 |
echo -e "\033[1mBold\033[0m"
echo -e "\033[4mUnderline\033[0m"
echo -e "\033[7mReverse\033[0m"
# Combining codes with semicolons
echo -e "\033[1;4;31mBold Underline Red\033[0m"
Cursor Positioning
| Sequence | Effect |
|---|---|
|
Home (0,0) |
|
Move to row r, column c |
|
Up n lines |
|
Down n lines |
|
Right n columns |
|
Left n columns |
|
Save cursor position |
|
Restore cursor position |
# Clear screen and home
printf "\033[2J\033[H"
# Position at row 10, column 60
printf "\033[10;60H"
# Multiplication table with positioning
printf "\033[2J\033[H"
for i in {1..10}; do
for j in {1..10}; do
printf "\033[%d;%dH%3d" "$i" "$((j*4))" "$((i*j))"
done
done
printf "\033[12;1H" # Move below table
Screen and Line Clearing
| Sequence | Effect |
|---|---|
|
Clear entire screen |
|
Clear from cursor to end of screen |
|
Clear from start to cursor |
|
Clear from cursor to end of line |
|
Clear entire line |
# Clear screen and home (common combo)
printf "\033[2J\033[H"
# Clear line and rewrite (for progress)
printf "\033[2K\rProcessing..."
# Hide/show cursor (for animations)
printf "\033[?25l" # Hide
printf "\033[?25h" # Show
Script Output Patterns
Define color variables once for the entire script:
# Color definitions
readonly RED='\033[31m'
readonly GREEN='\033[32m'
readonly YELLOW='\033[33m'
readonly BLUE='\033[34m'
readonly BOLD='\033[1m'
readonly RESET='\033[0m'
# Status functions
info() { printf "${BLUE}[INFO]${RESET} %s\n" "$1"; }
success() { printf "${GREEN}[OK]${RESET} %s\n" "$1"; }
warn() { printf "${YELLOW}[WARN]${RESET} %s\n" "$1" >&2; }
error() { printf "${RED}[FAIL]${RESET} %s\n" "$1" >&2; }
# Usage
info "Starting backup process"
success "vault-01 backup complete"
warn "Certificate expires in 7 days"
error "bind-01 unreachable"
Banners and Headers
# Simple banner
banner() {
local msg="$1"
local color="${2:-34}" # Default blue
printf "\033[1;${color}m=== %s ===\033[0m\n" "$msg"
}
banner "Starting Deployment"
banner "Warning" 33 # Yellow
banner "Error" 31 # Red
# Box banner with Unicode
box_banner() {
local msg="$1"
local len=${#msg}
local border=$(printf '═%.0s' $(seq 1 $((len + 4))))
printf "\033[1;36m╔%s╗\n║ %s ║\n╚%s╝\033[0m\n" \
"$border" "$msg" "$border"
}
box_banner "Production Deploy"
Progress Bar
progress_bar() {
local current=$1
local total=$2
local width=40
local percent=$((current * 100 / total))
local filled=$((current * width / total))
printf "\r["
for ((i=0; i<width; i++)); do
if ((i < filled)); then
printf "\033[42m \033[0m" # Green
else
printf "\033[100m \033[0m" # Gray
fi
done
printf "] %3d%%" "$percent"
}
printf "\033[?25l" # Hide cursor
for i in {0..100}; do
progress_bar "$i" 100
sleep 0.02
done
printf "\n\033[?25h" # Show cursor
AWK with ANSI Colors
AWK can generate colored output directly:
# Simple multiplication table
awk 'BEGIN {
for (i=1; i<=10; i++) {
for (j=1; j<=10; j++)
printf "%4d", i*j
print ""
}
}'
# With color highlighting (perfect squares green)
awk 'BEGIN {
for (i=1; i<=10; i++) {
for (j=1; j<=10; j++) {
val = i * j
if (int(sqrt(val))^2 == val)
printf "\033[32m%4d\033[0m", val
else
printf "%4d", val
}
print ""
}
}'
AWK Log Colorizer
# Colorize log files by level
colorize_logs() {
awk '
/ERROR|FAIL|CRITICAL/ { printf "\033[31m%s\033[0m\n", $0; next }
/WARN|WARNING/ { printf "\033[33m%s\033[0m\n", $0; next }
/INFO|NOTICE/ { printf "\033[34m%s\033[0m\n", $0; next }
/DEBUG|TRACE/ { printf "\033[90m%s\033[0m\n", $0; next }
/SUCCESS|OK/ { printf "\033[32m%s\033[0m\n", $0; next }
{ print }
'
}
# Usage
tail -f /var/log/app.log | colorize_logs
# Highlight IPs in cyan
cat /etc/hosts | awk '{
gsub(/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/, "\033[36m&\033[0m")
print
}'
# Highlight arbitrary pattern
highlight() {
local pattern="$1"
awk -v p="$pattern" '{
gsub(p, "\033[1;33m&\033[0m")
print
}'
}
cat config.yml | highlight "server"
AWK Colored Tables
# Status table with conditional coloring
echo "vault-01 10.50.1.30 up
ise-01 10.50.1.20 up
bind-01 10.50.1.90 down" | awk '
BEGIN {
printf "\033[1;4m%-15s %-12s %-8s\033[0m\n", "Hostname", "IP", "Status"
}
{
color = ($3 == "up") ? "\033[32m" : "\033[31m"
printf "%-15s %-12s %s%-8s\033[0m\n", $1, $2, color, $3
}'
# Dashboard with CPU/memory coloring
ps aux --no-headers | awk '
BEGIN {
printf "\033[1m%-10s %8s %8s %s\033[0m\n", "USER", "CPU%", "MEM%", "COMMAND"
}
NR <= 10 {
cpu_color = ($3 > 50) ? "\033[31m" : "\033[32m"
printf "%-10s %s%8.1f\033[0m %8.1f %s\n", $1, cpu_color, $3, $4, $11
}'
Respecting NO_COLOR
Scripts should disable colors when:
-
Output is piped (not a TTY)
-
NO_COLORenvironment variable is set -
Terminal is "dumb"
use_color() {
[[ -t 1 ]] && [[ "${TERM}" != "dumb" ]] && [[ -z "${NO_COLOR:-}" ]]
}
if use_color; then
RED='\033[31m'
GREEN='\033[32m'
RESET='\033[0m'
else
RED=''
GREEN=''
RESET=''
fi
# Now use $RED, $GREEN, $RESET throughout script
See: no-color.org/
Quick Reference
| Code | Effect |
|---|---|
|
Reset all |
|
Bold |
|
Red FG |
|
Green FG |
|
Yellow FG |
|
Blue FG |
|
Blue BG |
|
256-color FG |
|
256-color BG |
|
Clear screen |
|
Cursor home |
|
Cursor to row,col |
|
Clear to EOL |
|
Hide cursor |
|
Show cursor |