Overview
Purpose
bat is a modern replacement for cat written in Rust. It adds
syntax highlighting for over 200 languages, line numbers, Git change indicators,
automatic paging for long files, and a non-printing character display mode. It is a
drop-in upgrade for daily file viewing tasks.
Basic Syntax
bat [OPTIONS] [FILE]...
With no file argument, reads from stdin — making it a pipeline filter just like cat.
Key Strengths
bat shines for viewing source code, config files, scripts, and log files.
Git integration shows uncommitted changes inline with + and ~
markers. The pager (less by default) activates automatically when output
exceeds the terminal height. Works as a drop-in replacement in scripts with
--plain mode to suppress decorations.
Installation
RHEL / CentOS / Fedora
# Fedora
dnf install bat
# RHEL 8/9 — via EPEL
dnf install epel-release
dnf install bat
Debian / Ubuntu
apt install bat
# Note: On some Debian/Ubuntu versions the binary is named batcat
# Create an alias if needed:
mkdir -p ~/.local/bin
ln -s /usr/bin/batcat ~/.local/bin/bat
From GitHub releases (any distro)
# Download latest .tar.gz from https://github.com/sharkdp/bat/releases
# Example for x86_64:
wget https://github.com/sharkdp/bat/releases/latest/download/bat-musl_x86_64.tar.gz
tar xzf bat-musl_x86_64.tar.gz
cp bat-*/bat ~/.local/bin/
# Verify
bat --version
Common Options
| Option | Description |
|---|---|
-n, --number |
Show line numbers only (no other decorations) |
-A, --show-all |
Show non-printing characters (tabs, spaces, line endings) |
-p, --plain |
Plain output — no line numbers, no Git markers, no pager. Safe for scripts. |
-l, --language |
Force syntax language: bat -l yaml config |
-r, --line-range |
Show a line range: bat -r 20:40 file |
--diff |
Show only Git-changed lines with surrounding context |
--theme |
Choose a color theme: bat --theme=TwoDark file |
--list-themes |
List all available themes with preview |
--list-languages |
List all supported syntax languages |
--pager |
Set the pager: --pager "less -RF" or --pager never |
-H, --highlight-line |
Highlight a specific line: bat -H 42 file |
--wrap |
Line wrapping: never, auto, or character |
10 Detailed Examples
bat /etc/ssh/sshd_config
What This Does:
Displays the file with automatic syntax detection, line numbers, a header showing the filename and language, and Git change markers if the file is in a repository. If the file is longer than your terminal, the pager activates automatically.
Compared to cat:
cat /etc/ssh/sshd_config— plain text, no highlighting, scrolls past the topbat /etc/ssh/sshd_config— highlighted, numbered, paged, Git-aware
# Lines 50 through 80 only
bat -r 50:80 /var/log/syslog
# From line 100 to end of file
bat -r 100: /var/log/auth.log
# Just the first 25 lines
bat -r :25 /etc/nginx/nginx.conf
What This Does:
Displays only the specified line range with full syntax highlighting and correct line numbers showing the original file positions. Useful for jumping directly to a known problem area without scrolling through a large file.
SysAdmin Use Case:
vnu or a script tells you the error is on line 372 — go straight there:
bat -r 365:380 problem-file.html
# Show full file with Git change markers
bat deploy.sh
# Show only the changed lines with context
bat --diff deploy.sh
What This Does:
When viewing a file inside a Git repository, bat shows change markers in
the left gutter: + for added lines, ~ for modified
lines. The --diff flag filters to show only changed lines with
surrounding context — like a git diff but with full syntax
highlighting instead of raw diff output.
Practical Application:
Reviewing a config change before committing — see exactly what changed without switching to a separate diff tool.
# Pipe command output through bat for highlighting
journalctl -u nginx --since "1 hour ago" | bat -l log
# Highlight grep output
grep -n "error" /var/log/syslog | bat -l log --plain
# Pretty-print a JSON API response
curl -s https://api.example.com/status | bat -l json
# View a man page with bat
man ssh | bat -l man --plain
What This Does:
bat reads from stdin when no file is given, making it a drop-in filter
anywhere in a pipeline. The -l flag forces the syntax language
since bat cannot auto-detect from a pipe. Use --plain to suppress
line numbers and the pager when you want clean output for further processing.
Key Point:
bat auto-detects from filenames but needs -l when reading
from a pipe. Common language names: log, json,
yaml, bash, python, man.
# Show all non-printing characters
bat -A /etc/hosts
# Useful for spotting:
# ^I = tab character
# $ = end of line (shows CRLF vs LF)
# · = trailing spaces
What This Does:
The -A flag renders non-printing characters visibly. This is
the bat equivalent of cat -A but with syntax highlighting intact.
Invaluable for debugging config files that fail to parse due to invisible
characters.
SysAdmin Use Cases:
- Config file copied from Windows has CRLF line endings —
bat -Ashows the^M - YAML file fails to parse — trailing spaces or tabs are the usual culprit
- Shell script fails with "bad interpreter" — invisible character in the shebang line
# View several config files in sequence
bat /etc/ssh/sshd_config /etc/fail2ban/jail.conf /etc/hosts.allow
# Use a glob
bat /etc/nginx/conf.d/*.conf
# All Python files in current directory
bat *.py
What This Does:
bat displays multiple files sequentially, with a clear header between each
showing the filename. Each file gets its own syntax detection. This is
significantly more readable than cat file1 file2 which runs
the files together with no separation.
Practical Application:
Reviewing all nginx vhost configs in one pass:
bat /etc/nginx/sites-enabled/*
# A config file with no recognized extension
bat -l ini /etc/myapp/config
# A script with a non-standard extension
bat -l bash deploy.sh.bak
# Highlight a heredoc being built interactively
echo "SELECT * FROM users;" | bat -l sql
# Check what language bat detected
bat --language /etc/postfix/main.cf
What This Does:
bat detects syntax from file extensions and shebangs. When those are
absent or misleading, -l overrides the detection. Run
bat --list-languages to see all supported names.
Common Language Names:
bash,sh,zshpython,ruby,perljson,yaml,toml,ininginx,apache,ssh_configsql,xml,html,csslog,man,diff
# See all themes with a live preview
bat --list-themes
# Use a specific theme for one command
bat --theme=TwoDark /etc/ssh/sshd_config
# Set a permanent theme in config
mkdir -p ~/.config/bat
echo '--theme="TwoDark"' >> ~/.config/bat/config
# Popular themes for terminal use:
# TwoDark — dark, easy on the eyes
# gruvbox-dark — warm dark tones
# Coldark-Dark — high contrast dark
# Monokai Extended — classic dark
# GitHub — light, familiar
What This Does:
bat ships with dozens of color themes. The --list-themes
flag shows a live preview of each theme applied to a sample file so you
can choose without guessing. Theme preference goes in
~/.config/bat/config to persist across sessions.
# bat reads ~/.config/bat/config at startup
mkdir -p ~/.config/bat
cat > ~/.config/bat/config << 'EOF'
# Theme
--theme="TwoDark"
# Always show line numbers
--style="numbers,changes,header"
# Use less with follow mode available
--pager="less -RF"
# Wrap long lines
--wrap=never
EOF
# Verify config is loaded
bat --config-file
What This Does:
Any flag you use regularly can go in the config file — one flag per line.
bat reads it automatically at startup. The --style option controls
which decorations appear: numbers (line numbers),
changes (Git markers), header (filename bar),
grid (separator lines), full (everything).
Minimal Style Options:
--style=plain— no decorations, just highlighting--style=numbers— line numbers only--style=full— everything (default)
# Use bat as the man pager
export MANPAGER="sh -c 'col -bx | bat -l man -p'"
man grep
# Use bat as the git diff pager
git config --global core.pager bat
# fzf preview with bat (see fzf page for full setup)
export FZF_DEFAULT_OPTS="--preview 'bat --color=always {}'"
fzf
# Alias cat to bat (add to ~/.bashrc)
alias cat='bat --plain'
# Alias for plain output when scripting
alias batp='bat --plain --pager=never'
What This Does:
bat integrates cleanly into several common workflows. As a man pager it
syntax-highlights manual pages. As the git pager it highlights diffs. The
fzf integration provides a syntax-highlighted file preview panel. The
cat alias gives you bat everywhere without changing your
muscle memory.
Tip for Scripts:
Never alias bat to cat in scripts — use the explicit path or
bat --plain --pager=never when you need guaranteed plain output
for further processing. The alias is for interactive use only.
💡 ripgrep + bat — a natural pair
Use ripgrep to find the file and line, then bat to view the context:
rg -l "pattern" | xargs bat -r :50 or jump to a specific
hit: bat -r 45:55 $(rg -l "pattern" | head -1)
⚠️ bat vs. cat in scripts
bat is for human consumption. Its pager, colors, and decorations
break pipelines in non-interactive scripts. Use plain cat
in scripts. Use bat at the terminal. If you need bat in a pipeline,
always add --plain --pager=never --color=never.
Quick Reference
| Task | Command |
|---|---|
| View a file | bat filename |
| View lines 50–80 | bat -r 50:80 filename |
| Show Git changes only | bat --diff filename |
| Show non-printing chars | bat -A filename |
| Plain output (no decorations) | bat -p filename |
| Force syntax language | bat -l yaml filename |
| Highlight a specific line | bat -H 42 filename |
| List available themes | bat --list-themes |
| List supported languages | bat --list-languages |
| Pipe stdin through bat | journalctl -u sshd | bat -l log |
| No pager | bat --pager=never filename |
| View config file location | bat --config-file |