cheat sheet
bat
A cat clone with syntax highlighting, Git integration, line numbers, paging, and diff support. Drop-in replacement with many quality-of-life improvements for viewing files in the terminal.
bat — Better cat
What it is
bat is a free, open-source Rust-based replacement for cat maintained by David Peter on GitHub. It adds syntax highlighting for dozens of languages, Git change indicators in the margin, automatic paging via less, and line numbers — all while remaining a drop-in replacement for cat in pipelines. Reach for bat when you want to view source files or command output in the terminal with readable, colorized formatting; use plain cat when piping to other tools that expect unformatted text.
Installation
sudo apt install bat # Debian/Ubuntu (binary: batcat)
sudo dnf install bat # Fedora/RHEL
brew install bat # macOS / Linux via Homebrew
# Ubuntu alias
alias bat=batcat # add to ~/.bashrc
Output: (none — exits 0 on success)
Basic usage
bat file.txt # view with syntax highlighting + line numbers
bat file.py func.py # multiple files with headers
bat -n file.txt # show line numbers only (no frame)
bat -A file.txt # show all non-printable characters
bat --plain file.txt # plain output (no decorations), alias: -p
bat -p file.txt | less # pipe to pager manually
Output: (none — exits 0 on success)
Paging
bat automatically pipes output through $PAGER (defaulting to less) when content is taller than the terminal — the same behaviour you get from man. Set --paging=never to suppress this and treat bat like plain cat, which is preferable in scripts or when piping output to another tool.
bat file.txt # auto-pages through $PAGER (less) if tall
bat --paging=never file.txt # never page (like cat)
bat --paging=always file.txt # always page even if content fits
bat -P file.txt # shorthand for --paging=never
Output: (none — exits 0 on success)
Syntax and themes
bat bundles syntax definitions for dozens of languages and a selection of popular themes. Use --language to force a language when the file has no extension or a non-standard one, and --theme to override the default; set both permanently in ~/.config/bat/config.
bat --list-languages # list all supported languages
bat --list-themes # list all available themes
Output (bat --list-languages):
ABAP .abap
Ada .ada,.adb,.ads
Arduino .ino
AsciiDoc .adoc,.asciidoc
Assembly (x86_64) .asm
Awk .awk
Bash .bash,.bashrc,.sh
Batch File .bat,.cmd
C .c,.h
C# .cs
C++ .cpp,.cxx,.cc,.hh,.hpp
CSS .css
…
Output (bat --list-themes):
1337
Coldark-Cold
Coldark-Dark
DarkNeon
Dracula
GitHub
Monokai Extended
Monokai Extended Bright
Nord
OneHalfDark
…
bat -l python script # force language (no extension)
bat -l json output # treat file as JSON
bat -l sh - # read stdin as bash
bat --theme="Dracula" file.py # apply a specific theme
bat --theme=ansi file.txt # ANSI 16-colour theme (terminal-native)
bat --theme=GitHub file.md # light theme
Output: (none — exits 0 on success)
Set default theme
# In ~/.config/bat/config (or export BAT_CONFIG_PATH)
--theme="OneHalfDark"
--paging=never
--style=numbers,changes
Output: (none — exits 0 on success)
Style components
--style controls which UI elements bat renders around the content. Combine multiple components with commas; plain strips everything for clean pipeline output, while numbers,changes gives a minimal but informative view without the border grid.
bat --style=full file.txt # all decorations (default)
bat --style=plain file.txt # no decorations
bat --style=numbers file.txt # line numbers only
bat --style=changes file.txt # Git change markers only
bat --style=header file.txt # filename header only
bat --style=grid file.txt # separator lines only
bat --style=numbers,changes,header file.txt # combine
Output: (none — exits 0 on success)
Git integration
bat highlights modified, added, and deleted lines against the Git index automatically when --style=changes (included in full).
bat --diff file.txt # show only lines that differ from Git HEAD
bat --diff-context=5 file.txt # with 5 lines of context around diffs
Output: (none — exits 0 on success)
Line ranges
-r / --line-range restricts output to a slice of the file using start:end notation, with either end omittable. This is more convenient than head/tail because it preserves syntax highlighting and line-number context.
bat -r 10:20 file.txt # lines 10–20
bat -r :50 file.txt # first 50 lines (like head -50)
bat -r 100: file.txt # from line 100 to end (like tail -n +100)
bat -r 1:1 file.txt # first line only
bat -r :-10 file.txt # 0.26+: last 10 lines (negative relative range)
bat -r 30::5 file.txt # 0.26+: line 30 ±5 lines of context
Output (bat -r 10:20 file.txt — using a generic Python file as example):
10 def calculate_total(items):
11 """Sum all item prices in the list."""
12 total = 0.0
13 for item in items:
14 total += item.get("price", 0)
15 return total
16
17 def format_currency(amount, symbol="$"):
18 return f"{symbol}{amount:.2f}"
19
20 if __name__ == "__main__":
Reading from stdin
When no file argument is given, bat reads from stdin — but without an extension it cannot auto-detect the language. Pass -l <lang> explicitly to get syntax highlighting on piped content such as API responses or command output.
echo '{"key": "value"}' | bat -l json
curl -s https://api.example.com/data | bat -l json
git diff | bat --plain -l diff
Output (echo '{"key": "value"}' | bat -l json):
1 {
2 "key": "value"
3 }
Integration with other tools
bat is commonly wired in as the pager for man, the preview window for fzf, and the diff renderer for git — in each case --color=always or --plain keeps the output readable inside the host tool's interface.
# bat as MANPAGER (colourised man pages)
export MANPAGER="sh -c 'col -bx | bat -l man -p'"
export MANRASTER_BIN=cat
# Use bat for previews in fzf
fzf --preview 'bat --color=always {}'
# Use bat in git diff
git config --global core.pager 'bat --paging=always'
git config --global interactive.diffFilter 'bat --plain'
# Use with ripgrep for syntax-highlighted search output
rg --json pattern | bat -l json
# Preview files found by fd
fd -e py | xargs bat --style=header,numbers
# Replace less as a pager
export PAGER="bat --paging=always"
Output: (none — exits 0 on success)
Config file
Location: ~/.config/bat/config (or $(bat --config-file))
--theme="OneHalfDark"
--paging=auto
--style=numbers,changes,header
--map-syntax="*.config:XML"
--map-syntax="Dockerfile*:Dockerfile"
--map-syntax=".env:Shell Script"
--italic-text=always
Custom syntax mappings
bat --map-syntax="*.conf:INI" httpd.conf
bat --map-syntax="Makefile*:Makefile" GNUmakefile
Output: (none — exits 0 on success)
Aliases and wrappers
Aliasing cat to bat --paging=never works well interactively but can surprise scripts that expect plain output; a safer pattern is a separate short alias (e.g., b) while keeping cat untouched. On Debian/Ubuntu the binary is named batcat, so an alias or symlink is required before any cat=bat setup makes sense.
# ~/.bashrc
alias cat='bat --paging=never'
alias less='bat --paging=always'
alias batdiff='bat --diff'
# Colourised help
alias bathelp='bat --plain --language=help'
help fzf | bat --plain -l help
Output: (none — exits 0 on success)
bat vs cat
| Scenario | Preference |
|---|---|
| View a code file interactively | bat |
Pipeline (cmd | process) | cat or bat -p |
| Binary/raw file | cat (bat refuses binary) |
| Man pages | bat -l man |
| Quick peeks | bat -r 1:30 |
Environment variables
bat reads several environment variables that override flags and config-file directives, which makes them ideal for per-shell or per-session customisation without editing ~/.config/bat/config. Use them in your shell rc file for global defaults, or set them inline (BAT_THEME=ansi bat file.py) to tweak a single invocation.
| Variable | Purpose |
|---|---|
BAT_THEME | Default theme name (e.g. Dracula, ansi, GitHub) |
BAT_THEME_DARK | Theme used when terminal is detected as dark (0.25+, with --theme=auto) |
BAT_THEME_LIGHT | Theme used when terminal is detected as light (0.25+, with --theme=auto) |
BAT_STYLE | Default style components (numbers,changes,header) |
BAT_PAGER | Pager used by bat (overrides PAGER) — set to less -RF for color + auto-quit |
BAT_PAGING | always / never / auto — overrides --paging |
BAT_TABS | Tab width (e.g. 4) |
BAT_CONFIG_PATH | Alternate config file location |
BAT_CONFIG_DIR | Alternate config directory (for syntaxes/themes) |
# Inline override for one invocation
BAT_THEME="ansi" bat README.md
# Permanent defaults in ~/.bashrc or ~/.zshrc
export BAT_THEME="OneHalfDark"
export BAT_STYLE="numbers,changes,header"
export BAT_PAGER="less -RF"
export BAT_PAGING="auto"
Output: (none — exits 0 on success)
Highlighting specific lines (-H)
-H / --highlight-line draws attention to one or more line numbers by inverting their background colour, while still rendering the surrounding file normally. Combine with -r to show only a window of code around the highlighted lines — useful for code reviews, bug reports, or pasting a focused snippet into chat.
bat -H 42 src/app.py # highlight line 42
bat -H 42 -H 58 src/app.py # highlight multiple lines
bat -H 40:50 src/app.py # highlight a range
bat -H 42 -r 35:50 src/app.py # show lines 35–50 with 42 highlighted
Output (bat -H 12 -r 10:15 sample.py):
10 def calculate_total(items):
11 """Sum all item prices in the list."""
12 total = 0.0 ← highlighted line (inverted background)
13 for item in items:
14 total += item.get("price", 0)
15 return total
Multiple line ranges
-r can be repeated to print disjoint slices of the same file, separated by a snip marker — handy when reviewing a function definition alongside the call site without scrolling through the whole file.
bat -r 1:20 -r 80:100 src/app.py # two windows from one file
bat -r 1:5 -r 50:55 -r 100:105 file # three windows
Output: (none — exits 0 on success)
Diff mode
--diff (alias -d) restricts output to lines that differ from the Git index, with a few lines of context. This is a quick way to focus on uncommitted changes without launching git diff proper, and it keeps bat's syntax highlighting and line numbers intact.
bat --diff app.py # show only changed regions
bat -d --diff-context=10 app.py # 10 lines of context around each change
bat -d *.py # diff every Python file in cwd
Output: (none — exits 0 on success)
Showing non-printable characters
-A / --show-all renders tabs as ␉, line feeds as ␊, carriage returns as ␍, and other control characters with explicit glyphs. This is essential for debugging Windows/Unix line-ending mismatches, stray trailing whitespace, or BOM markers in config files.
bat -A script.sh # reveal CRLF, tabs, trailing whitespace
bat -A --tabs=0 script.sh # don't expand tabs (raw glyphs only)
Output (bat -A on a file with mixed line endings):
1 #!/bin/bash␊
2 set -euo pipefail␍␊
3 ␉echo "hello world" ␊
Pager interactions
bat's default pager is less with flags that preserve ANSI colour and quit automatically on short output. When a custom PAGER is set system-wide (e.g. most, more), set BAT_PAGER separately to keep bat's pager configured for colour without affecting other tools.
# Recommended less flags when used as bat's pager
export BAT_PAGER="less -RFX"
# -R pass through ANSI colour codes
# -F quit if entire content fits on one screen
# -X don't clear screen on exit
# Disable paging entirely (treat like cat)
export BAT_PAGING="never"
# Pipe to your own pager
bat --paging=never file.py | less -R
# 0.26+: built-in 'minus' pager (no external 'less' required)
bat --pager=builtin file.py
Output: (none — exits 0 on success)
Cache and custom syntaxes/themes
bat cache --build rebuilds the syntax and theme cache after dropping new .sublime-syntax or .tmTheme files into $(bat --config-dir)/syntaxes/ or themes/. This is how you add support for niche languages (e.g. nginx.conf, dockerfile-variants) or custom-tuned theme colours.
bat --config-dir # print config dir (where syntaxes/ and themes/ live)
mkdir -p "$(bat --config-dir)/syntaxes" "$(bat --config-dir)/themes"
# Drop in custom files, then rebuild
cp ~/Downloads/MyTheme.tmTheme "$(bat --config-dir)/themes/"
bat cache --build # regenerate cache
bat --list-themes | grep -i mytheme # confirm it loaded
bat cache --clear # remove cached syntaxes/themes
Output (bat cache --build):
Writing theme set to /home/alice/.config/bat/metadata.bin … okay
Writing syntax set to /home/alice/.config/bat/syntaxes.bin … okay
fzf integration
bat is the de-facto preview renderer for fzf because it adds syntax highlighting and line numbers inside the preview window. The {} token is replaced by the highlighted entry; --color=always is required so colour codes survive the pipe into fzf.
# File picker with syntax-highlighted preview
fzf --preview 'bat --style=numbers --color=always --line-range :500 {}'
# Bind a fzf-bat function to Ctrl-O
fb() {
local file
file=$(fzf --preview 'bat --color=always --style=numbers {}') || return
${EDITOR:-vim} "$file"
}
# Preview lines around a ripgrep match
rg --line-number --no-heading --color=always '' \
| fzf --ansi --delimiter : \
--preview 'bat --color=always --highlight-line {2} {1}' \
--preview-window 'up,60%,+{2}/2'
Output: (none — exits 0 on success)
Replacing cat in shell aliases
Aliasing cat directly can surprise scripts that source your rc file, so a defensive pattern uses a shell function that disables paging when stdout is not a terminal. This keeps bat interactive at the prompt and pipeline-safe inside scripts or substitutions.
# Interactive-only bat-as-cat (safe for pipelines)
cat() {
if [ -t 1 ]; then
command bat --paging=never "$@"
else
command cat "$@"
fi
}
# Short alias for "view this file nicely"
alias view='bat --paging=always --style=full'
# Plain-text bat for pipelines (no decorations)
alias bcat='bat --paging=never --style=plain'
Output: (none — exits 0 on success)
Syntax-aware grep
Piping bat -p output through grep preserves ANSI colour codes from syntax highlighting, so search results retain their language-aware colouring. --color=always is required because bat strips colour when stdout is not a TTY.
bat --color=always -p app.py | grep --color=always "def "
bat --color=always -p *.json | grep -E '"(name|version)"'
# Combine with -r to grep inside a slice
bat --color=always -p -r 1:200 huge.log | grep ERROR
Output: (none — exits 0 on success)
bat vs cat vs less vs ccat
| Tool | Highlighting | Paging | Git markers | Line numbers | Notes |
|---|---|---|---|---|---|
cat | No | No | No | -n flag | POSIX, fastest, pipeline-safe |
less | Limited (-R) | Yes | No | -N flag | Interactive viewer, search, jumping |
ccat | Yes | No | No | No | Older Go tool, fewer languages |
bat | Yes (Sublime grammars) | Auto via less | Yes (--style=changes) | Yes (-n) | The de-facto modern replacement |
Common recipes
# View only the first 30 lines (like head, with colour)
bat -r 1:30 file.py
# Tail-equivalent: last 100 lines with highlighting
bat -r $(( $(wc -l < file.log) - 100 )): file.log
# Diff two files with side-by-side highlighting via delta or git
git diff --no-index -- a.py b.py | bat -l diff
# Render a Markdown file with headings preserved
bat -l md README.md
# Print stdin as JSON when the content type isn't auto-detected
curl -s https://api.example.com/users | bat -l json
# Show all .py files in a project with headers and line numbers
fd -e py | xargs bat --style=header,numbers
# View a man-page-equivalent with bat colouring
help cd | bat -l help -p
Output: (none — exits 0 on success)
Squeeze blank lines
-s / --squeeze-blank (0.25+) collapses runs of consecutive blank lines into a single blank line, matching cat -s behaviour. Pair with --squeeze-limit=N to keep up to N blanks instead of just one — handy for inspecting heavily-padded log files or generated source without losing every paragraph break.
bat -s server.log # collapse runs of blanks to a single blank
bat --squeeze-blank --squeeze-limit=2 notes.md # keep at most 2 blanks in a row
Output: (none — exits 0 on success)
Strip ANSI input
--strip-ansi={never,always,auto} (0.25+) removes ANSI escape sequences from bat's input before re-highlighting, which lets you re-pretty-print log output that was already coloured by another tool. With auto, bat strips ANSI when a syntax is detected so the language grammar applies cleanly.
some-noisy-cmd | bat --strip-ansi=always -l log
make 2>&1 | bat --strip-ansi=auto -l make
Output: (none — exits 0 on success)
Binary as text
--binary=as-text (0.25+) forces bat to render a file even when it detects non-text bytes — useful for partially-binary fixtures, firmware blobs with embedded ASCII strings, or .env files containing odd UTF sequences. By default bat refuses binary input and prints a warning.
bat --binary=as-text firmware.bin
bat --binary=as-text odd-encoding.txt
Output: (none — exits 0 on success)
Automatic light/dark theme
--theme=auto (0.25+) picks between BAT_THEME_DARK and BAT_THEME_LIGHT based on the terminal's reported background colour, which keeps bat readable when you toggle macOS Dark Mode or a tmux popup that swaps palette. Falls back to BAT_THEME if the terminal doesn't expose its colour scheme.
export BAT_THEME_DARK="OneHalfDark"
export BAT_THEME_LIGHT="GitHub"
bat --theme=auto file.py # pick based on detected background
Output: (none — exits 0 on success)
Shell completions
--completion <shell> (0.25+) prints completion script for bash, zsh, or fish directly from the binary — no separate package install. Source the output from your shell rc to get tab-complete for every flag and subcommand.
bat --completion bash > ~/.local/share/bash-completion/completions/bat
bat --completion zsh > ~/.zfunc/_bat
bat --completion fish > ~/.config/fish/completions/bat.fish
Output: (none — exits 0 on success)
Troubleshooting
| Symptom | Likely cause / fix |
|---|---|
bat: command not found on Ubuntu | Binary is batcat; add alias bat=batcat |
| No colour in pipelines | Add --color=always (bat auto-disables colour off-TTY) |
Garbled output through less | Set BAT_PAGER="less -R" to pass through ANSI |
Theme missing from --list-themes | Run bat cache --build after adding .tmTheme files |
bat refuses to display a file | Probably detected binary content; force with --show-all or cat |
| Wrong language detected | Force with -l <lang> or add a --map-syntax rule |
--diff shows nothing | File matches the Git index — no changes to highlight |
bat --config-fileprints the path to your config file.bat --generate-config-filecreates a commented template at that path.
bat --acknowledgementslists every syntax-and-theme third-party licence bundled with the binary — useful when shippingbatinside a corporate environment that requires open-source disclosure.
Sources
- sharkdp/bat releases — canonical release notes
- bat CHANGELOG.md — full changelog including unreleased master entries
- Release v0.25.0 —
--squeeze-blank,--strip-ansi,--binary=as-text,--completion, auto theme - Release v0.26.0 — negative line ranges, line-range context, built-in
minuspager, Windows/ARM64 - Release v0.26.1 — paging in
--help, hang fixes