Linux脚本中用echo加ANSI转义码实现颜色输出最轻量通用,需记基础色码(如\033[32m绿)、必加-e参数、结尾用\033[0m重置;封装log_info等函数可复用并加时间戳;重定向时需用[-t 1]判断终端动态关闭颜色;tput更语义化但需兜底兼容。

Linux脚本里用echo加ANSI转义码实现颜色输出
直接在echo里拼接ANSI颜色码是最轻量、最通用的做法,不需要额外依赖,所有主流shell(bash/zsh/sh)都支持。关键是记住几个基础颜色码:\033[32m(绿色)、\033[33m(黄色)、\033[31m(红色),结尾统一用\033[0m重置样式。
常见错误是忘了重置——比如某行echo -e "\033[31mERROR\033[0m"漏了\033[0m,后续所有终端输出都会变红。
- 必须加
-e参数,否则\033会被当普通字符串输出 - 别用
\e代替\033,某些老版本dash(Ubuntu的默认/bin/sh)不识别\e - 颜色码只影响当前
echo命令,不会“污染”后续命令,但终端状态会保留(所以重置很重要)
封装成log_info、log_warn、log_error函数复用
重复写echo -e "\033[32mINFO: ...\033[0m"既啰嗦又易错,直接封装成函数,还能统一加时间戳和前缀。
log_info() { echo -e "\033[32m[$(date +'%H:%M:%S')] INFO: $*\033[0m"; }
log_warn() { echo -e "\033[33m[$(date +'%H:%M:%S')] WARN: $*\033[0m"; }
log_error() { echo -e "\033[31m[$(date +'%H:%M:%S')] ERROR: $*\033[0m"; }
使用时直接log_info "config loaded"就行。注意:$*比$@更安全,能避免空格分割问题;如果脚本可能被sh执行(非bash),别用$(date),改用`date`兼容性更好。
重定向到文件时颜色码会变成乱码,得动态关闭
当用户执行./script.sh > output.log,颜色码会原样写进文件,打开就是一堆^[[32m这样的控制字符。解决方案是检测输出是否连接到终端:
if [ -t 1 ]; then COLOR_INFO="\033[32m" COLOR_WARN="\033[33m" COLOR_ERROR="\033[31m" COLOR_RESET="\033[0m" else COLOR_INFO="" COLOR_WARN="" COLOR_ERROR="" COLOR_RESET="" fi
然后函数里用echo -e "${COLOR_INFO}INFO: $*${COLOR_RESET}"。这个判断很关键——-t 1检查标准输出(fd 1)是否为终端,不是硬编码test -t或tty -s,更可靠。
用tput替代硬编码ANSI码,但要注意兼容性陷阱
tput setaf 2(绿色)比记\033[32m更语义化,且能适配不同终端类型(比如某些哑终端会自动降级为无色)。但问题在于:tput在非交互式环境(如cron、管道、重定向)下可能报错或返回空,导致日志前缀丢失。
- 必须用
tput setaf 2 2>/dev/null || echo ""兜底,否则脚本可能因tput失败而中断 -
tput查不到setaf时(比如极简容器镜像),不如直接fallback到ANSI码 - 颜色编号:2=绿,3=黄,1=红,和ANSI一致,不用重新记
真正复杂的点不在怎么加颜色,而在于“什么时候不该加”——日志被重定向、被管道传递、被CI系统捕获时,颜色不仅是干扰,还可能破坏结构化解析。所以判断-t 1这一步,绕不开。


















