跳到主要内容
ansicode

LESS 颜色 —— 通过 LESS_TERMCAP_*、LESS=R、MANPAGER 给 man 页面着色

less 读取 LESS_TERMCAP_* 环境变量为它从 groff 重叠看到的粗体 / 下划线 / standout 序列着色 —— 这是给 man 页面着色的规范配方。另一半是 LESS=R(或 LESS='-R -F -X'),它让上游管道里(来自 git log --color=alwaysls --color=alwaysgrep --color=always)已有的 SGR 字节穿过 less 到达终端,而非被剥离。下方七段复制即用片段覆盖完整地图:规范的 6 变量 LESS_TERMCAP_* 集合、LESS 环境标志、MANPAGER + MANROFFOPT + GROFF_NO_SGR 互动、lesspipe / LESSOPEN 预处理、bat 作为着色 MANPAGER、diff-so-fancy / delta 作为增强的 git pager,以及按 shell 接线。

配置片段

LESS_TERMCAP_* —— 让 man 页面着色的权威 6 变量集

less 读取 LESS_TERMCAP_* 环境变量来覆盖它默认从 terminfo 取的粗体 / 下划线 / standout 序列。当 man 调用 less 分页输出时,groff 产出的 nroff 用退格-重叠(b\bbo\bol\bld\bd = 粗体)与下划线-重叠(_\bb_\bo_\bl_\bd = 斜体 / 参数名)—— less 解析这些并发出配置好的 LESS_TERMCAP_* 字节。六个变量重要:md(起粗体)、me(结束粗体 / 闪烁 / standout)、us(起下划线)、ue(结束下划线)、so(起 standout —— 用于状态 / 提示行与搜索匹配)、se(结束 standout)。可选 mb(起闪烁)通常复制自 md,避免闪烁内容被隐藏。值是原始 ANSI / VT 转义字节 —— 在 shell 配置里直接写 \e[01;31m 字面形式。

shell / env
# The canonical 6-var set — drop into ~/.bashrc / ~/.zshrc verbatim.
# Bold red for keywords / commands (md), green underline for arguments
# (us), yellow standout for status line + search matches (so).

export LESS_TERMCAP_md=$'\e[01;31m'      # start bold        (man: keywords)
export LESS_TERMCAP_me=$'\e[0m'          # end bold / blink / standout
export LESS_TERMCAP_us=$'\e[01;32m'      # start underline   (man: args / files)
export LESS_TERMCAP_ue=$'\e[0m'          # end underline
export LESS_TERMCAP_so=$'\e[01;44;33m'   # start standout    (status / search hit)
export LESS_TERMCAP_se=$'\e[0m'          # end standout
export LESS_TERMCAP_mb=$'\e[01;31m'      # start blink — copy md so it stays visible

# Verify they are exported with the right bytes (decode the ESC):
env | grep LESS_TERMCAP | cat -v
#   should show ^[[01;31m etc — the ^[ is ESC (0x1b), the rest is the SGR

# See the effect immediately — load a man page:
man ls

# Quick a/b test — unset, reload, compare:
( unset LESS_TERMCAP_md LESS_TERMCAP_me LESS_TERMCAP_us \
        LESS_TERMCAP_ue LESS_TERMCAP_so LESS_TERMCAP_se; \
  man ls )
# vs the current shell session with the vars set.

# Note the $'...' syntax — bash / zsh ANSI-C quoting that turns \e into
# the literal ESC byte. If your shell does NOT support $'...' (older sh /
# dash) use printf:
#   LESS_TERMCAP_md=$(printf '\e[01;31m'); export LESS_TERMCAP_md

LESS=R —— 上游直接发出原始 SGR 时的颜色透传

LESS_TERMCAP_* 覆盖 less 自己通过解析输入来加颜色的情形。另一种情形是上游已经发出 SGR 字节(如 git log --color=alwaysls --color=alwaysgrep --color=alwayscolordiffdiff-so-fancy)—— 这些字节需要透传 less 到终端。默认 less 会剥离控制字符并显示 ^[[31m 字面噪音。修复是 -R 标志(或 --RAW-CONTROL-CHARS),它让 SGR 字节通过同时仍清理其它控制字符。LESS 环境变量设置每次 less 调用默认应用的标志 —— LESS=R 让 raw-control-chars 成为全局默认。现代 less(v530 起,2017)也支持 -r(小写)传递所有控制字符 —— 用 -R 而非 -r,除非确实需要渲染其它控制字符。

shell / env
# Set the default once — every less invocation gains -R:
export LESS=R

# Optional companion flags many users add to LESS:
export LESS='-R -F -X'
#   -R   keep SGR bytes (already covered above)
#   -F   quit if output fits one screen (skip the pager-trap on short files)
#   -X   skip the alt-screen restore (so scrollback retains the pager content)

# These are the same flags git auto-sets when invoking its DEFAULT pager.
# Custom pagers (core.pager, PAGER, MANPAGER) do NOT inherit them — set
# LESS globally instead.

# One-shot — no env, flags on the command line:
git log --color=always --oneline | less -R
grep --color=always -rn TODO src/    | less -R
ls --color=always -la                 | less -R

# Without -R (the default), you see literal noise:
ls --color=always | less
#   src/  app/  ESC[01;34mlib^[[0mESC[m  ...  (ugly)

# With -R, colour passes through:
ls --color=always | less -R
#   src/  app/  (bold blue lib)  ...        (correct)

# Verify LESS is honoured by the binary:
echo "$LESS"
less --help 2>&1 | grep -E 'RAW|environment' | head

MANPAGER 与 PAGER —— 现代 man 两者皆读,但 MANPAGER 胜出

man 按此顺序查找 pager:$MANPAGER$PAGER、编译期默认(通常 less)。设置 MANPAGER 让你给 man 一个与日常 less 不同的 pager —— 在希望 man 始终强制颜色渲染但保持普通 less 调用不变时很有用。规范安全值是 MANPAGER='less -R'。在 groff 足够新(1.18.1+,2008)且设置 MANROFFOPT=-c 的发行版上,groff 直接发出 SGR 而非退格-重叠 —— 此时 LESS_TERMCAP_* 失效(less 不再解析重叠),需要 MANPAGER='less -R' 才能让 SGR 通过。现代 Debian / Ubuntu / Arch 默认就是这个配置;BSD 与较旧 RHEL 仍走重叠路径。两者都设 —— MANPAGER='less -R'LESS_TERMCAP_* —— 透明地覆盖两条路径。

shell / env
# Set both — covers groff-SGR path AND backspace-overstrike path:
export MANPAGER='less -R'
export MANROFFOPT='-c'              # tell groff to emit SGR (modern groff)

# Plus the LESS_TERMCAP_* vars from snippet 1 (for the overstrike path).

# Check which path your distro uses — run man on any page, then in less
# press 'v' to drop into $EDITOR (or use !cat) and look at the raw bytes:
#
#   If you see "b\bbo\bol\bld" overstrike → backspace-overstrike path,
#                                              LESS_TERMCAP_* is in play.
#   If you see "\x1b[1mbold\x1b[0m"        → groff-SGR path,
#                                              MANPAGER='less -R' is what matters.

# Force the overstrike path even on a modern distro (so LESS_TERMCAP_*
# applies again — useful when debugging custom palettes):
export GROFF_NO_SGR=1

# Test:
man ls
# Try changing LESS_TERMCAP_md to a glaring colour and reload to confirm
# which path is active:
export LESS_TERMCAP_md=$'\e[01;45m'        # purple background
man ls    # if you see purple text → overstrike path; else → SGR path

# When piping man output (e.g. into grep / a file) the formatting is
# normally stripped because the pager is not a TTY. Preserve it with:
MAN_KEEP_FORMATTING=1 man ls | head -50    # keeps overstrike bytes
# Then strip later with col -b:
MAN_KEEP_FORMATTING=1 man ls | col -b | head -50    # plain text

LESSOPEN / lesspipe —— 在 less 看到输入前预处理

less 对每个输入文件运行 $LESSOPEN(可选 $LESSCLOSE),让用户在字节抵达 pager 前有机会变换 —— 多数发行版自带 lesspipe.sh(Debian / Ubuntu)或 lesspipe.lua(Arch),通过 /etc/profile.d/less.sh 中的 eval "$(lesspipe)" 接线。开箱即用让 less archive.tar.gz 显示目录列表、less foo.pdf 显示提取文本、less foo.deb 显示包元数据 —— 比单独 less 的输入支持广得多。颜色角度:lesspipesource-highlight(或 highlightbatpygmentize)集成,使 less foo.py 显示带语法高亮的 Python 源代码。通过 LESSOPEN='| /usr/bin/src-hilite-lesspipe.sh %s' 配置高亮器,并添加 LESS=" -R"(注意前导空格)保持颜色透传。

shell / env
# Default Debian / Ubuntu setup (already in /etc/profile.d/less.sh):
export LESSOPEN="| /usr/bin/lesspipe %s"
export LESSCLOSE="/usr/bin/lesspipe %s %s"

# Verify it's working — should show metadata not raw bytes:
less /usr/lib/x86_64-linux-gnu/libc.so.6      # ELF binary → strings dump
less /etc/os-release                          # text file → straight through
less ./some.tar.gz                            # archive → tar tvfz listing

# Add syntax highlighting for source code via source-highlight:
sudo apt install source-highlight              # Debian / Ubuntu
brew install source-highlight                  # macOS

# Wire it as the pre-processor — note leading space in LESS:
export LESSOPEN="| /usr/bin/src-hilite-lesspipe.sh %s"
export LESS=" -R"                              # leading space prevents typoed
                                               # binary name issues

# Test it:
less app/page.tsx                              # should show syntax-highlighted TS
less script.sh                                 # should show syntax-highlighted bash
less /etc/nginx/nginx.conf                     # should show coloured nginx config

# Disable for one invocation (debugging):
LESSOPEN= less raw.log
less --no-lessopen raw.log                     # explicit flag, less v530+

# Combine with bat for richer highlighting (snippet 5 explores bat more):
export LESSOPEN="| /usr/bin/bat --color=always --paging=never %s"

bat / batcat —— 带语法高亮的着色 less 替代

bat(作者 sharkdp —— Rust)是 cat / less 混合体,增加语法高亮、行号、Git 修改标记、与遵循 less 键位的分页模式(bat -p 不分页)。它既是 cat 的直接替代(alias cat=bat),也可作为 MANPAGER 提供带语法高亮代码块的着色 man 页面。Debian / Ubuntu 上二进制重命名为 batcat(更早的无关 bat 包占用了名字)—— Arch / Fedora / Homebrew 仍以 bat 安装。通过 bat --list-themes 查主题(OneHalfDark / Dracula / gruvbox-dark / Solarized (light) / ansi 仅终端调色板)。BAT_THEME 环境变量设默认;BAT_PAGER='less -R' 覆盖 pager。--color={auto,always,never}NO_COLOR 都尊重。

shell / env
# Install:
#   Arch:        pacman -S bat
#   Debian/Ubuntu: apt install bat   (binary is "batcat", not "bat")
#   Fedora:      dnf install bat
#   macOS:       brew install bat

# Debian / Ubuntu workaround — alias batcat back to bat:
alias bat='batcat'

# Use as a cat replacement (paging only when output exceeds terminal):
bat app/page.tsx                              # syntax-highlighted, line numbers
bat -p app/page.tsx                           # plain mode (no header, no pager)
bat -A binary.dat                             # show non-printable as escapes

# Use as MANPAGER for colourised man pages:
export MANPAGER="sh -c 'col -bx | bat -l man -p'"
#   col -bx       strip backspace-overstrike (otherwise bat sees garbage)
#   bat -l man    syntax = man (highlights options + section refs)
#   bat -p        plain mode (no header)

# Theme + style configuration:
export BAT_THEME='OneHalfDark'                # any theme from --list-themes
export BAT_STYLE='numbers,changes,header'     # opt-in column set
export BAT_PAGER='less -R'                    # override default pager

# Verify which binary, where the config file lives:
bat --version
bat --config-file                              # path; create + edit to persist
bat --generate-config-file                     # write a fully-commented template

# Pipe coloured input into bat (preserve SGR):
git log --color=always --oneline | bat --paging=always
diff -u old.txt new.txt | bat -l diff

# Use as drop-in cat (with caveats — bat exits with paging on long output):
alias cat='bat -p'                             # plain mode = no extra UI

diff-so-fancy / delta —— 增强的着色 diff pager

两个针对 git / diff 输出的流行 pager 替代,都假设 LESS=" -R"(或 LESS=FRX)已设。diff-so-fancy(作者 so-fancy —— Perl)清理统一 diff 输出:移除 +++ / --- 标头、用细分隔符替换 @@ hunk 标记、用更亮 SGR 重新着色 + / - 行。通过 git config --global core.pager "diff-so-fancy | less --tabs=4 -RFX" 接线。delta(作者 dandavison —— Rust)更进一步:并排模式、语法高亮代码、可配置行号 + 加减标记、Git-blame 集成。通过 git config --global core.pager delta 接线(delta 自动检测自己是 pager 并应用)。delta~/.gitconfig [delta] 节读配置 —— 设 features = side-by-side line-numbers decorations 走现代外观。两者都尊重 NO_COLOR--color=never

shell / env
# Install:
#   diff-so-fancy: brew install diff-so-fancy   (or npm i -g diff-so-fancy)
#   delta:         brew install git-delta       (or cargo install git-delta)

# diff-so-fancy — wire into git core.pager:
git config --global core.pager 'diff-so-fancy | less --tabs=4 -RFX'
git config --global interactive.diffFilter 'diff-so-fancy --patch'

# Optional colour tuning that diff-so-fancy assumes:
git config --global color.diff-highlight.oldNormal    'red bold'
git config --global color.diff-highlight.oldHighlight 'red bold 52'
git config --global color.diff-highlight.newNormal    'green bold'
git config --global color.diff-highlight.newHighlight 'green bold 22'
git config --global color.diff.meta       'yellow'
git config --global color.diff.frag       'magenta bold'
git config --global color.diff.commit     'yellow bold'
git config --global color.diff.old        'red bold'
git config --global color.diff.new        'green bold'
git config --global color.diff.whitespace 'red reverse'

# delta — wire it as the pager (auto-detects):
git config --global core.pager delta
git config --global interactive.diffFilter 'delta --color-only'
git config --global delta.navigate true
git config --global delta.light false
git config --global delta.line-numbers true
git config --global delta.side-by-side true
git config --global delta.syntax-theme 'OneHalfDark'

# Disable for one command:
git --no-pager diff
git -c core.pager=cat diff

# Test:
git diff HEAD~1
git log --oneline -p | head -50

# Pipe a raw diff (not via git) into either tool:
diff -u old.txt new.txt | diff-so-fancy | less -R
diff -u old.txt new.txt | delta

按 shell 接线 —— bash · zsh · fish · csh

权威接线把上述片段全部组合:LESS_TERMCAP_* 给 man 着色、LESS='-R -F -X' 走 SGR 透传 + 合理退出 + 保留 scrollback、MANPAGER='less -R' 让现代 groff 的 SGR 流过、可选 BAT_THEME 走语法高亮代码。每个 shell 导出方式不同。/ls-colors/grep-colors 的 macOS bash 双坑同样适用 —— ~/.bashrc 仅在非登录 shell 运行,但 Terminal.app 启动登录 shell,故 env 导出请放 ~/.bash_profile(macOS 默认 zsh 时放 ~/.zprofile)。Fish 需要通过 printf-into-set 模式拿到字面 ESC 字节,因为 $'\e' ANSI-C 引用是 bash / zsh 专属语法。

shell / env
# ~/.bashrc (Linux) or ~/.bash_profile (macOS Terminal.app):
export LESS_TERMCAP_md=$'\e[01;31m'     # bold        → bold red
export LESS_TERMCAP_me=$'\e[0m'
export LESS_TERMCAP_us=$'\e[01;32m'     # underline   → bold green
export LESS_TERMCAP_ue=$'\e[0m'
export LESS_TERMCAP_so=$'\e[01;44;33m'  # standout    → bold yellow-on-blue
export LESS_TERMCAP_se=$'\e[0m'
export LESS_TERMCAP_mb=$'\e[01;31m'
export LESS='-R -F -X'
export MANPAGER='less -R'
export MANROFFOPT='-c'
export PAGER='less'

# ~/.zshrc / ~/.zprofile (same syntax, $'...' works in zsh too):
export LESS_TERMCAP_md=$'\e[01;31m'
# ... (same six exports)
export LESS='-R -F -X'
export MANPAGER='less -R'

# ~/.config/fish/config.fish — fish has NO $'...' quoting, use printf:
set -gx LESS_TERMCAP_md (printf '\e[01;31m')
set -gx LESS_TERMCAP_me (printf '\e[0m')
set -gx LESS_TERMCAP_us (printf '\e[01;32m')
set -gx LESS_TERMCAP_ue (printf '\e[0m')
set -gx LESS_TERMCAP_so (printf '\e[01;44;33m')
set -gx LESS_TERMCAP_se (printf '\e[0m')
set -gx LESS_TERMCAP_mb (printf '\e[01;31m')
set -gx LESS '-R -F -X'
set -gx MANPAGER 'less -R'

# ~/.cshrc / ~/.tcshrc — printf inside backticks, setenv (no = sign):
setenv LESS_TERMCAP_md "`printf '\e[01;31m'`"
setenv LESS_TERMCAP_me "`printf '\e[0m'`"
# ... (same six setenv)
setenv LESS '-R -F -X'
setenv MANPAGER 'less -R'

# Verify:
man ls          # should show coloured keywords + underlined args
echo "$LESS"    # should print "-R -F -X"
env | grep -E 'LESS_TERMCAP|MANPAGER' | cat -v   # show with ^[ visible

# macOS double-trap reminder — these only run on LOGIN shell:
#   ~/.bash_profile, ~/.zprofile, ~/.profile
# These only run on NON-login (subshell) shell:
#   ~/.bashrc, ~/.zshrc

LESS_TERMCAP_* 槽位参考

七个 LESS_TERMCAP_* 环境变量 —— 每个起或结束什么、配对的起 / 结束变量、less 赋予它的角色。me 重置被 md / mb / so 共享;ue 仅与 us 配对;se 仅与 so 配对。

LESS_TERMCAP_* 槽位参考
环境变量配对含义用途
LESS_TERMCAP_mdme起粗体man 页面关键字 / 命令名 / 标题
LESS_TERMCAP_memd/mb/so结束粗体 / 闪烁 / standout(单一重置)三个起始序列的共享重置
LESS_TERMCAP_usue起下划线(man 中为斜体)man 页面参数名 / 文件名 / 强调
LESS_TERMCAP_ueus结束下划线下划线起始序列的配对重置
LESS_TERMCAP_sose起 standout(反色高亮)less 底部的状态 / 提示行;搜索匹配高亮
LESS_TERMCAP_seso结束 standoutstandout 起始序列的配对重置
LESS_TERMCAP_mbme起闪烁(罕见)极少使用;从 md 复制以保持闪烁内容可见

本站覆盖周边 ANSI / pager / man / diff 生态的相邻页面。