跳到主要内容
ansicode

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` 形式。

shell / env
# 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_COLOR

GREP_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=` 空。

shell / env
# 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`。

shell / env
# 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 file

ripgrep —— --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`。

shell / env
# 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        # honoured

ag(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 接棒前积累的庞大安装基数仍被广泛使用。

shell / env
# 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 输入。

shell / env
# 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` 输出看起来一致。

shell / env
# ~/.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_profile

GREP_COLORS 槽位参考

每个 GREP_COLORS 槽位键、含义、GNU grep 默认值,以及触发它的 grep 标志组合。底部两个布尔键(`rv`、`ne`)不接值 —— 出现即为信号。

GREP_COLORS 槽位参考
含义默认触发条件
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 / 匹配器生态的相邻页面。