Skip to main content
ansicode
Bash / shell

ANSI escape codes in Bash / shell

Bash has two reliable ways to emit escape bytes: printf with \033 / \x1b (POSIX-portable), and tput (terminfo-driven, the safest because it adapts to $TERM). echo -e works in bash but breaks in dash / sh; avoid it in portable scripts. The literal $'\e[...' ANSI-C quoting form is bash/zsh-only but very readable.

Recommended libraries

  • tput

    ncurses-bundled binary: tput setaf 1 emits red foreground escape for the current $TERM. Use this in scripts that need to work on dumb / 16-colour / 256-colour terminals alike.

  • gum (charmbracelet)

    Pre-styled shell primitives — gum style, gum spin, gum choose, gum confirm. Wraps lipgloss / bubbletea for shell scripts.

  • dialog / whiptail

    Classic full-screen menus / inputs / progress over curses. whiptail is the lighter, BSD-licensed clone shipped with Debian.

  • ncurses

    C library, but bash scripts can call helper binaries like clear, reset, tput, infocmp that ship with it.

Idiomatic patterns

printf with octal — the portable form
printf '\033[1;31m%s\033[0m %s\n' 'error:' 'permission denied'
Named tput colours — terminfo-aware
RED=$(tput setaf 1)
BOLD=$(tput bold)
RESET=$(tput sgr0)

printf '%s%serror:%s permission denied\n' "$BOLD" "$RED" "$RESET"
Bash ANSI-C quoting ($'...') — readable
red=$'\e[31m'
reset=$'\e[0m'
echo "${red}error${reset}: permission denied"
Respect NO_COLOR
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
  RED=$'\e[31m'; RESET=$'\e[0m'
else
  RED=""; RESET=""
fi
printf '%serror:%s permission denied\n' "$RED" "$RESET"

Related sequences

Other languages