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

bash
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

bash
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.

bash
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.

bash
bat --list-languages          # list all supported languages
bat --list-themes             # list all available themes

Output (bat --list-languages):

arduino
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):

yaml
1337
Coldark-Cold
Coldark-Dark
DarkNeon
Dracula
GitHub
Monokai Extended
Monokai Extended Bright
Nord
OneHalfDark

bash
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

bash
# 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.

bash
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).

bash
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.

bash
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):

python
   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.

bash
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):

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.

bash
# 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))

text
--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

bash
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.

bash
# ~/.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

ScenarioPreference
View a code file interactivelybat
Pipeline (cmd | process)cat or bat -p
Binary/raw filecat (bat refuses binary)
Man pagesbat -l man
Quick peeksbat -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.

VariablePurpose
BAT_THEMEDefault theme name (e.g. Dracula, ansi, GitHub)
BAT_THEME_DARKTheme used when terminal is detected as dark (0.25+, with --theme=auto)
BAT_THEME_LIGHTTheme used when terminal is detected as light (0.25+, with --theme=auto)
BAT_STYLEDefault style components (numbers,changes,header)
BAT_PAGERPager used by bat (overrides PAGER) — set to less -RF for color + auto-quit
BAT_PAGINGalways / never / auto — overrides --paging
BAT_TABSTab width (e.g. 4)
BAT_CONFIG_PATHAlternate config file location
BAT_CONFIG_DIRAlternate config directory (for syntaxes/themes)
bash
# 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.

bash
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):

python
   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.

bash
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.

bash
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.

bash
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):

bash
   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.

bash
# 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.

bash
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):

arduino
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.

bash
# 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.

bash
# 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.

bash
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

ToolHighlightingPagingGit markersLine numbersNotes
catNoNoNo-n flagPOSIX, fastest, pipeline-safe
lessLimited (-R)YesNo-N flagInteractive viewer, search, jumping
ccatYesNoNoNoOlder Go tool, fewer languages
batYes (Sublime grammars)Auto via lessYes (--style=changes)Yes (-n)The de-facto modern replacement

Common recipes

bash
# 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.

bash
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.

bash
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.

bash
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.

bash
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.

bash
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

SymptomLikely cause / fix
bat: command not found on UbuntuBinary is batcat; add alias bat=batcat
No colour in pipelinesAdd --color=always (bat auto-disables colour off-TTY)
Garbled output through lessSet BAT_PAGER="less -R" to pass through ANSI
Theme missing from --list-themesRun bat cache --build after adding .tmTheme files
bat refuses to display a fileProbably detected binary content; force with --show-all or cat
Wrong language detectedForce with -l <lang> or add a --map-syntax rule
--diff shows nothingFile matches the Git index — no changes to highlight

bat --config-file prints the path to your config file. bat --generate-config-file creates a commented template at that path.

bat --acknowledgements lists every syntax-and-theme third-party licence bundled with the binary — useful when shipping bat inside a corporate environment that requires open-source disclosure.

Sources