Shell Scripting ANSI Colours Terminal UI Intermediate May 2026

Shell Scripting Colour & UI in Terminal

Master ANSI colour codes, text attributes, progress bars, spinners, formatted tables with printf, and safe colour detection. Build professional-looking terminal UIs that work across all environments.

Colour and formatting transform a wall of text into something operators can scan at a glance during incidents. Good terminal UI is not decoration — it reduces time-to-diagnosis and makes scripts feel trustworthy. These patterns use standard ANSI codes that work in every modern terminal.

BASH
# ── Colour constants ──────────────────────────────────────
# Use $'...' quoting for escape sequences
readonly RESET=$'\033[0m'
readonly BOLD=$'\033[1m'
readonly DIM=$'\033[2m'
readonly UNDERLINE=$'\033[4m'

# Foreground colours
readonly BLACK=$'\033[30m'  RED=$'\033[31m'    GREEN=$'\033[32m'
readonly YELLOW=$'\033[33m' BLUE=$'\033[34m'   MAGENTA=$'\033[35m'
readonly CYAN=$'\033[36m'   WHITE=$'\033[37m'

# Bright foreground colours
readonly BRED=$'\033[91m'   BGREEN=$'\033[92m'  BYELLOW=$'\033[93m'
readonly BBLUE=$'\033[94m'  BWHITE=$'\033[97m'

# ── Usage ─────────────────────────────────────────────────
echo "${GREEN}✔ Success${RESET}"
echo "${RED}✘ Error${RESET}"
echo "${YELLOW}⚠ Warning${RESET}"
echo "${BOLD}${BLUE}INFO${RESET}: Deployment starting"
echo "${DIM}[2026-05-01 10:14:02]${RESET} Processing..."

# ── Detect if terminal supports colour ────────────────────
supports_colour() {
  [[ -t 1 ]] && [[ "$(tput colors 2>/dev/null)" -ge 8 ]]
}

# Disable colour when piped or redirected
if ! supports_colour; then
  RED=""; GREEN=""; YELLOW=""; RESET=""; BOLD=""
fi

# Or respect NO_COLOR env variable (https://no-color.org)
[[ -n "${NO_COLOR:-}" ]] && RED="" GREEN="" RESET=""
BASH
# ── Aligned columns ───────────────────────────────────────
printf "%-20s %-15s %-8s %s\n" "HOST" "STATUS" "DISK" "UPTIME"
printf "%-20s %-15s %-8s %s\n" "────────────────────" "───────────────" "────────" "──────"

for srv in web-01 web-02 db-01; do
  status="${GREEN}UP${RESET}"
  printf "%-20s %-24s %-8s %s\n" \
    "${srv}" "${status}" "38%" "14d 3h"
done

# ── Progress bar ──────────────────────────────────────────
progress_bar() {
  local pct="${1}"
  local width=40
  local filled=$(( pct * width / 100 ))
  local empty=$(( width - filled ))
  printf "\r  [${GREEN}%${filled}s${RESET}%${empty}s] %3d%%" \
    "$(printf '#%.0s' $(seq 1 "${filled}"))" \
    "" "${pct}"
}

for i in {0..100..5}; do
  progress_bar "${i}"
  sleep 0.1
done
echo ""

# ── Spinner ───────────────────────────────────────────────
spin() {
  local msg="${1}"
  local pid="${2}"
  local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
  local i=0
  while kill -0 "${pid}" 2>/dev/null; do
    printf "\r  ${CYAN}%s${RESET} %s" \
      "${frames[$((i % ${#frames[@]}))]}" "${msg}"
    (( i++ ))
    sleep 0.1
  done
  printf "\r  ${GREEN}✔${RESET} %s\n" "${msg}"
}

long_task &
spin "Running long task..." $!
BASH
#!/usr/bin/env bash
# Coloured logging functions for any script

readonly _R=$'\033[0m'    # reset
readonly _B=$'\033[1m'    # bold
readonly _G=$'\033[32m'   # green
readonly _Y=$'\033[33m'   # yellow
readonly _RE=$'\033[31m'  # red
readonly _C=$'\033[36m'   # cyan
readonly _D=$'\033[2m'    # dim

log_info()  { printf "%b  INFO%b  %s\n"  "${_C}${_B}" "${_R}" "$*"; }
log_ok()    { printf "%b  OK   %b  %s\n"  "${_G}${_B}" "${_R}" "$*"; }
log_warn()  { printf "%b  WARN %b  %s\n"  "${_Y}${_B}" "${_R}" "$*"; }
log_error() { printf "%b  ERROR%b  %s\n" "${_RE}${_B}" "${_R}" "$*" >&2; }
log_dim()   { printf "%b  %s%b\n"         "${_D}" "$*" "${_R}"; }
log_step()  { printf "\n%b▸ %s%b\n"      "${_B}" "$*" "${_R}"; }

# Usage
log_step "Deployment Phase 1: Validation"
log_info "Checking prerequisites..."
log_ok   "mysql client found"
log_warn "Disk 78% full — recommend cleanup"
log_error "DB_PASS not set"
log_dim  "[2026-05-01 10:14:02] Debug: connecting to prod-db-01:3306"
bash — coloured output demo
vriddh@prod-01:~/scripts$./deploy.sh
▸ Deployment Phase 1: Validation
INFO Checking prerequisites...
OK mysql client found
OK curl found
WARN Disk 78% full — recommend cleanup
▸ Deployment Phase 2: Deploy
INFO Uploading application files...
[████████████████████████████████ ] 82%
⚠ When not to use colour — Always check [[ -t 1 ]] (stdout is a terminal) before emitting colour codes. Colour in logs files makes them hard to grep. Respect the NO_COLOR environment variable. Provide a --no-colour flag in any user-facing tool. Scripts piped into others should produce clean output.
✔ Terminal UI rules — Store colour codes in readonly variables with $'...' quoting. Always end coloured output with ${RESET}. Use printf over echo -e for portability. For progress bars, use \r to overwrite the current line. Check terminal support with [[ -t 1 ]] and disable colour when stdout is not a tty.