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。