GREP_COLORS —— grep、ripgrep、ag 的 ANSI 颜色
GNU grep 读取 GREP_COLORS 环境变量(复数,带 S —— grep 2.5.2 / 2007 年 3 月起替代遗留的单一颜色 GREP_COLOR)。它是一个冒号分隔的 key=SGR 串,独立为输出每个元素着色:匹配文本、文件名、行号、字节偏移、分隔符、选中行、上下文行。ripgrep 不读 GREP_COLORS —— 它用自有的 --colors <type>:<attribute>:<value> 点号语法。ag(the_silver_searcher)用专用 --color-line-number= / --color-match= / --color-path= 标志。下方七段复制即用片段覆盖三种工具的完整地图,外加经典的管道再过 grep 陷阱(颜色字节破坏朴素子串匹配)。
配置片段
GREP_COLOR(遗留,单一颜色)vs GREP_COLORS(当前,按槽位)
GNU grep 历史上读单个环境变量 GREP_COLOR(单数,无 S),其值是单个 SGR 字符串,仅作用于匹配文本 —— 其它元素(文件名、行号、分隔符)都硬编码。从 GNU grep 2.5.2(2007 年 3 月)起规范环境变量改为 GREP_COLORS(复数,带 S)—— 冒号分隔的 key=SGR 字符串,独立为输出每个元素着色。GREP_COLOR 仍因向后兼容被读取,但 GREP_COLORS=mt=... 会覆盖它。两者都设置时 GREP_COLORS 胜出。陈旧的 .bashrc 常因遗留原因仍固定 GREP_COLOR=01;31 —— 替换为下方完整的 GREP_COLORS 形式。
# Legacy — single colour for matched text only (pre-2007 grep):
export GREP_COLOR='01;31' # bold red match, only
# Current — per-slot, colours every output element independently:
export GREP_COLORS='mt=01;31:fn=35:ln=32:bn=32:se=36'
# mt=01;31 matched text → bold red
# fn=35 filename prefix → magenta
# ln=32 line number prefix → green
# bn=32 byte offset prefix → green
# se=36 separator (: / -- ) → cyan
# Check which env is set:
env | grep -E '^GREP_COLOR'
# If both are set, GREP_COLORS wins — drop the legacy one to avoid confusion:
unset GREP_COLORGREP_COLORS —— 冒号分隔的 key=SGR 槽位语法
单个冒号分隔的 key=value 字符串,每个输出元素一对。键有三类:两字母槽位标记(匹配文本、文件名、行号、字节偏移、分隔符、选中行、上下文行),布尔开关(rv 在传入 -v 时交换选中与上下文;ne 跳过 Erase-In-Line 清除转义 —— 当终端的 \x1b[K 实现有 bug 时设置),以及 SGR-only 值(去掉前导 \x1b[ 与末尾 m —— 裸 01;31 = 粗体红、38;5;208 = 256 调色板橙、38;2;255;128;0 = 24 位真彩色)。布尔键不接 =value(出现即为信号)。未列出的槽位回退到 grep 默认:mt=01;31、fn=35、ln=32、bn=32、se=36、sl= 空、cx= 空。
# All 11 GREP_COLORS slots, set explicitly:
export GREP_COLORS='\
mt=01;31:\
ms=01;31:\
mc=01;31:\
fn=35:\
ln=32:\
bn=32:\
se=36:\
sl=:\
cx=:\
rv:\
ne'
# What each slot does:
# mt matched text on EITHER selected or context line — shorthand
# for setting ms + mc to the same value
# ms matched text on a selected line (default: 01;31 bold red)
# mc matched text on a context line (default: 01;31 bold red)
# fn filename prefix (default: 35 magenta)
# ln line number prefix (-n) (default: 32 green)
# bn byte offset prefix (-b) (default: 32 green)
# se separator (: between fn/ln/match; --
# between groups; - in context output) (default: 36 cyan)
# sl the entire selected (matching) line (default: empty = inherit)
# cx the entire context line (-A/-B/-C) (default: empty = inherit)
# rv boolean — swaps sl<->cx when -v (default: off)
# ne boolean — skip Erase-In-Line escape (default: off)
# Truecolor since grep 3.0+ (no real version gate — passes bytes through):
export GREP_COLORS='mt=38;2;255;128;0;01:fn=38;5;213:ln=38;5;120'
# mt=38;2;255;128;0;01 match → bold truecolor orange
# fn=38;5;213 filename → 256-palette pink
# ln=38;5;120 line number → 256-palette mint
# Verify by piping a small file through it:
printf 'one\ntwo\nthree\n' | grep --color=always two--color={auto,always,never} —— 单次调用覆盖
grep --color={auto,always,never}(也接受 --colour,英式拼写 —— 两种都有效)。auto 为合理默认 —— TTY 上着色、管道时剥离。always 在管道时也强制着色;never 禁用。grep 不带任何标志的默认是 never —— 多数发行版在 ~/.bashrc / /etc/profile.d/colorls.sh 中把 grep 别名为 grep --color=auto 以翻转此默认。egrep / fgrep / rgrep 接受同一标志。--color 不带值(grep --color pattern)等同于 auto。从 GNU grep 3.5(2020)起尊重通用 NO_COLOR=1 环境变量 —— 覆盖任何形式的 --color。
# Three modes:
grep --color=auto pattern file # TTY only (the sensible default)
grep --color=always pattern file # force through pipes
grep --color=never pattern file # disable entirely
grep --color pattern file # bare flag = auto
NO_COLOR=1 grep pattern file # universal opt-out (grep 3.5+)
# Canonical aliases — drop into ~/.bashrc / ~/.zshrc:
alias grep='grep --color=auto'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
# Force colour into a pager that renders SGR:
grep --color=always -rn pattern src/ | less -R
# Force colour into an HTML converter for blog / code review:
grep --color=always -rn TODO src/ | aha > todos.html
# Defeat the alias for one invocation (use the binary directly):
\\grep pattern file # bypasses alias
command grep pattern file # same
/usr/bin/grep pattern file # explicit path
# British spelling — same flag, same behaviour:
grep --colour=always pattern fileripgrep —— --colors 标志与更丰富的点号语法
ripgrep(rg,作者 BurntSushi —— Rust 实现的现代替代)不读 GREP_COLORS。其自有语法用重复的 --colors <type>:<attribute>:<value> 标志,type 取 path / line / column / match,attribute 取 fg / bg / style / none,value 取命名颜色(red / green / blue / yellow / magenta / cyan / white / black)、256 表 256 调色板、或 0xRRGGBB 表真彩色。style 接受 bold / intense / nobold / nointense / underline / nounderline。多个 --colors 标志可叠加。通过 RIPGREP_CONFIG_PATH=$HOME/.ripgreprc 持久化,每行一个标志。ripgrep 也尊重 --color={auto,always,never,ansi}(ansi 变体即便在 Windows 上也总是发出 SGR 而非走 console API)以及 NO_COLOR。
# One-shot — override match colour to bright yellow on red background:
rg --colors 'match:fg:yellow' \
--colors 'match:bg:red' \
--colors 'match:style:bold' \
pattern src/
# All four element types:
rg --colors 'path:fg:magenta' \
--colors 'path:style:bold' \
--colors 'line:fg:green' \
--colors 'line:style:nointense' \
--colors 'column:fg:cyan' \
--colors 'match:fg:red' \
--colors 'match:style:bold' \
pattern src/
# Truecolor (0xRRGGBB form):
rg --colors 'match:fg:0xff8000' \
--colors 'match:style:bold' \
pattern src/
# 256 palette:
rg --colors 'match:fg:256' \
--colors 'match:fg:208' \
pattern src/
# Persist via ~/.ripgreprc (one flag per line, no quotes):
cat > ~/.ripgreprc <<'EOF'
--colors=match:fg:yellow
--colors=match:bg:red
--colors=match:style:bold
--colors=path:fg:magenta
--colors=line:fg:green
--smart-case
EOF
echo 'export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"' >> ~/.bashrc
# Color modes — note 'ansi' is the Windows-emit-anyway variant:
rg --color=auto pattern # default — TTY only
rg --color=always pattern # force through pipe (Unix-style ANSI)
rg --color=ansi pattern # force ANSI even on Windows (skip console API)
rg --color=never pattern # disable
NO_COLOR=1 rg pattern # honouredag(the_silver_searcher)—— --color-* 标志 + AG_COLORS 环境变量
ag(the_silver_searcher,作者 ggreer —— C 实现,早于 ripgrep)的形状又不同:三个专用标志 --color-line-number=<SGR>、--color-match=<SGR>、--color-path=<SGR>,每个接受原始 SGR 参数字符串(去掉前导 \x1b[ 与末尾 m)。默认:--color-line-number=1;33(粗体黄)、--color-match=30;43(黑底黄)、--color-path=1;32(粗体绿)。通过 ~/.agrc 持久化(每行一个标志、不带前导 --)—— ag 在解析 argv 前读取它。尊重 --color / --nocolor(不用 =value 形式,两个独立标志)以及通用 NO_COLOR。注:ag 不支持 path:fg:red 风格的点号语法 —— 只支持原始 SGR 数字形式。ag 已不再活跃开发(最后发布 2021),但因速度优势与 ripgrep 接棒前积累的庞大安装基数仍被广泛使用。
# One-shot — override match colour to bright red bg + bold white fg:
ag --color-match='1;37;41' pattern src/
# All three element flags together:
ag --color-line-number='1;36' \
--color-match='1;37;41' \
--color-path='1;35' \
pattern src/
# 256-palette + truecolor (ag passes bytes through, no validation):
ag --color-match='38;5;208;01' pattern src/ # palette orange
ag --color-match='38;2;255;128;0;01' pattern src/ # 24-bit orange
# Toggle colour (no =value form for these flags):
ag --color pattern src/ # force on
ag --nocolor pattern src/ # force off
NO_COLOR=1 ag pattern src/ # universal opt-out (honoured)
# Persist via ~/.agrc — one flag per line, NO leading -- and NO quotes:
cat > ~/.agrc <<'EOF'
--color-line-number=1;36
--color-match=1;37;41
--color-path=1;35
--smart-case
--hidden
EOF
# Verify ag is picking it up:
ag --help 2>&1 | grep -E 'color|agrc'管道再过 grep 的陷阱 —— 颜色字节破坏朴素子串匹配
一个经典的真实坑:cmd --color=always | grep something(或 ls --color=always | grep .conf、或 git log --color=always | grep TODO)会静默失败,因为 SGR 字节现在是 grep 看到的每个字节流的一部分 —— 它们包裹着上游输出中匹配的子串。你的 grep something 现在在查找字面字节序列 s o m e t h i n g,但输入是 s \x1b[1;31m o m e \x1b[0m t h i n g(或类似碎片)。三种正确处理:(1) 内层 grep 使用 --color=never,(2) 先用 sed 剥离 SGR,(3) 使用 --color=auto(默认)并信任 TTY 检测。不要让 SGR 静默进入 grep 输入。
# WRONG — the inner grep sees SGR bytes split across the substring,
# the match silently fails:
ls --color=always | grep '.conf'
git log --color=always --oneline | grep 'TODO'
# RIGHT (1) — inner grep with --color=never strips colour BEFORE matching:
ls --color=always | grep --color=never '.conf'
git log --color=always --oneline | grep --color=never 'TODO'
# RIGHT (2) — strip SGR with sed before the inner grep sees it:
ls --color=always | sed -E 's/\x1b\[[0-9;]*m//g' | grep '.conf'
# RIGHT (3) — use --color=auto (the default) and trust TTY detection,
# the OUTER command will skip colour because the pipe is not a TTY:
ls --color=auto | grep '.conf' # ls strips colour automatically
git log --oneline | grep 'TODO' # git pager also off when piped
# Symptom check — if you suspect SGR is leaking into a grep, decode it:
cmd --color=always | head -c 200 | cat -v
# look for ^[[31m / ^[[0m sequences — those are SGR bytes
# General-purpose ansi-strip wrapper (drop into ~/.bashrc):
strip_ansi() { sed -E 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\x1b\][^\x07]*\x07//g'; }
# Usage: ls --color=always | strip_ansi | grep '.conf'按 shell 接线 —— bash · zsh · fish · csh
GREP_COLORS 是普通 env 变量;任何能导出 env 的 shell 都能设置。每个 shell 接线不同,且与 /ls-colors 同样有 macOS bash 双坑 —— ~/.bashrc 仅在非登录 shell 运行,但 Terminal.app 启动登录 shell,故 env 导出请放 ~/.bash_profile(macOS 默认 zsh 时放 ~/.zprofile)。fish 用 set -gx 全局导出。ripgrep 用 RIPGREP_CONFIG_PATH env 指向 .ripgreprc 文件(任何 shell)。ag 由二进制自动读取 ~/.agrc —— 不需要 env 变量。下方配方一致地设置三种工具,使用统一调色板让 grep / rg / ag 输出看起来一致。
# ~/.bashrc (Linux) or ~/.bash_profile (macOS Terminal.app):
export GREP_COLORS='mt=01;33;41:fn=35:ln=32:bn=32:se=36'
export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"
alias grep='grep --color=auto'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
# ~/.zshrc / ~/.zprofile (macOS default since 10.15):
export GREP_COLORS='mt=01;33;41:fn=35:ln=32:bn=32:se=36'
export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"
alias grep='grep --color=auto'
# ~/.config/fish/config.fish — set -gx is global-export:
set -gx GREP_COLORS 'mt=01;33;41:fn=35:ln=32:bn=32:se=36'
set -gx RIPGREP_CONFIG_PATH ~/.ripgreprc
alias grep 'grep --color=auto'
# ~/.cshrc / ~/.tcshrc — setenv, no = sign:
setenv GREP_COLORS 'mt=01;33;41:fn=35:ln=32:bn=32:se=36'
setenv RIPGREP_CONFIG_PATH ~/.ripgreprc
alias grep 'grep --color=auto'
# ~/.ripgreprc — one flag per line, no quotes:
cat > ~/.ripgreprc <<'EOF'
--colors=match:fg:yellow
--colors=match:bg:red
--colors=match:style:bold
--colors=path:fg:magenta
--colors=line:fg:green
EOF
# ~/.agrc — same one-flag-per-line, NO leading -- in some versions
# (always test with: ag --color-match='1;33' pattern . 2>&1 | head):
cat > ~/.agrc <<'EOF'
--color-line-number=1;36
--color-match=1;33;41
--color-path=1;35
EOF
# macOS double-trap reminder — these only run on LOGIN shell:
# ~/.bash_profile, ~/.zprofile, ~/.profile
# These only run on NON-login (subshell) shell:
# ~/.bashrc, ~/.zshrc
# Terminal.app spawns login shells; iTerm2 + VS Code terminal default
# to non-login. Source one from the other for symmetry:
# echo '[ -r ~/.bashrc ] && . ~/.bashrc' >> ~/.bash_profileGREP_COLORS 槽位参考
每个 GREP_COLORS 槽位键、含义、GNU grep 默认值,以及触发它的 grep 标志组合。底部两个布尔键(rv、ne)不接值 —— 出现即为信号。
| 键 | 含义 | 默认 | 触发条件 |
|---|---|---|---|
| mt | 选中或上下文行上的匹配文本(ms+mc 的简写) | 01;31 | 未传 -v 时始终 |
| ms | 选中(匹配)行上的匹配文本 | 01;31 | 默认 grep 输出 |
| mc | 上下文行上的匹配文本 | 01;31 | 配合 -A / -B / -C / -v |
| fn | 文件名前缀 | 35 | 配合 -H 或递归(-r) |
| ln | 行号前缀 | 32 | 配合 -n |
| bn | 字节偏移前缀 | 32 | 配合 -b |
| se | 分隔符(fn/ln/match 间的 :;分组间的 --;上下文中的 -) | 36 | 始终(出现前缀时) |
| sl | 整行选中(匹配)行(不含 mt 匹配部分) | (empty = inherit) | 默认 grep 输出 |
| cx | 整行上下文行(不含 mt 匹配部分) | (empty = inherit) | 配合 -A / -B / -C |
| rv | 布尔 —— 当 -v(反向匹配)生效时交换 sl<->cx 角色 | off | 配合 -v |
| ne | 布尔 —— 跳过 Erase-In-Line `\x1b[K` 转义(针对有 bug 的终端的变通) | off | 仅作罕见变通 |
相关参考
本站覆盖周边 ANSI / pager / 匹配器生态的相邻页面。
- Git 颜色配置配套按工具页面 —— git 的 color.ui / 按命令的键 / 槽位调色板 / core.pager + LESS=FRX / 把 --color=always 管到 less -R。
- LS_COLORS 环境变量配套按工具页面 —— LS_COLORS 语法(类型 + 扩展名标记)、dircolors 工作流、BSD LSCOLORS 分歧、eza / exa。
- 剔除 ANSI 转义码事后剔除已捕获
grep --color=always输出中 SGR 字节的正则 —— 归档日志输出时使用。 - ANSI 常见坑点相邻问题的「症状 → 成因 → 修复」—— 颜色字节破坏 grep 子串匹配、
--color=always到了错误的下游、旧工具未尊重 NO_COLOR。