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

\033[

Octal

Most portable (POSIX)

\x1b[

Hexadecimal

Widely supported

\e[

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

\033[H

Home (0,0)

\033[r;cH

Move to row r, column c

\033[nA

Up n lines

\033[nB

Down n lines

\033[nC

Right n columns

\033[nD

Left n columns

\033[s

Save cursor position

\033[u

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

\033[2J

Clear entire screen

\033[J

Clear from cursor to end of screen

\033[1J

Clear from start to cursor

\033[K

Clear from cursor to end of line

\033[2K

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_COLOR environment 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

Quick Reference

Code Effect

\033[0m

Reset all

\033[1m

Bold

\033[31m

Red FG

\033[32m

Green FG

\033[33m

Yellow FG

\033[34m

Blue FG

\033[44m

Blue BG

\033[38;5;Nm

256-color FG

\033[48;5;Nm

256-color BG

\033[2J

Clear screen

\033[H

Cursor home

\033[r;cH

Cursor to row,col

\033[K

Clear to EOL

\033[?25l

Hide cursor

\033[?25h

Show cursor