TechEarl

bat: A cat Clone With Syntax Highlighting

bat is a cat command replacement that adds syntax highlighting, line numbers, and Git change markers. Install it, alias cat to it carefully, and know the --plain, --style, --paging, and --diff flags that make it behave well in scripts and pipes.

Ishan Karunaratne⏱️ 9 min readUpdated
Share thisCopied
bat is a cat command replacement with syntax highlighting, line numbers, and Git change markers. Install it, alias cat with --paging=never, and use --plain, --style, --paging, and --diff in scripts and pipes.

bat file.py prints the file the way cat does, but with syntax highlighting, line numbers, and a Git change gutter down the left edge. It is a drop-in cat command replacement for reading files at the terminal: same job, a lot more readable. bat is a single Rust binary by Sharkdp, the same author as fd and hyperfine, and it pipes through a pager automatically when the output is longer than the screen.

The one thing to know up front: bat is built for a human looking at a terminal, not for a pipe. When you redirect its output or pipe it into another command, it detects that and falls back to plain, undecorated text, exactly like cat. So bat file | grep foo works the way you expect. But the moment you alias cat to bat you change the default reading experience, and there are a couple of flags (--paging, --style) you need to set so it does not surprise you. The rest of this page is install, the alias, and the flags that matter.

Install bat

On most distros it is one package. The name of the package and the name of the binary do not always match, which is the first thing that trips people up.

bash
# Debian / Ubuntu (binary is "batcat", not "bat")
sudo apt install bat

# Fedora
sudo dnf install bat

# Arch
sudo pacman -S bat

# macOS (Homebrew)
brew install bat

On Debian and Ubuntu the executable is installed as batcat, because the name bat already belongs to an unrelated package (the Bacula Administration Tool). Everywhere else the binary is bat. If you are on Debian or Ubuntu and want to type bat, add a shell alias or a symlink:

bash
mkdir -p ~/.local/bin
ln -s /usr/bin/batcat ~/.local/bin/bat

Check the version once it is in:

bash
bat --version
text
bat 0.26.1

Read a file

bash
bat src/main.rs

That prints main.rs with Rust syntax highlighting, a line-number column, a header showing the filename, and (if the file is inside a Git repo) + / ~ markers in the gutter for lines added or changed since the last commit. If the file is longer than your terminal, bat opens it in less so you can scroll, then drops you back at the prompt when you quit.

You can read several files at once, same as cat:

bash
bat Cargo.toml src/main.rs

Each gets its own header so you can tell where one file ends and the next begins.

Alias cat to bat (the right way)

The reason people install bat is to type cat and get the nice output. The naive alias has two problems, and both are fixable:

bash
# In ~/.bashrc or ~/.zshrc
alias cat='bat --paging=never'

--paging=never is the important part. Plain cat never pages; it dumps the whole file and returns. If you alias cat to bare bat, then cat shortfile suddenly opens a pager for files that used to just print, which breaks muscle memory and any interactive habit you have. --paging=never makes the alias behave like cat: print and return. You still get bat proper (with paging) when you type bat directly.

This is safe for scripts too, because bat already detects when its output is not a terminal and strips all decoration. A script that calls cat file and now hits the alias will still get clean bytes, not escape codes. (Aliases are not expanded in non-interactive shells anyway, so most scripts never see the alias at all. The terminal-detection behavior is the real safety net.)

The flags that matter

bat has a lot of options. These are the handful you actually reach for.

FlagWhat it does
-p, --plainNo line numbers, no Git gutter, no header. Pass it twice (-pp) to also disable paging. The closest thing to raw cat.
--style=<components>Pick exactly which decorations show. Comma-separated: numbers, changes, header, grid, full, plain.
--paging=<when>auto (default), never, or always. never is what the cat alias wants.
-l, --language=<lang>Force the syntax language when bat guesses wrong, e.g. bat -l json config for a JSON file with no extension.
--theme=<name>Pick the highlight theme. bat --list-themes shows what is installed.
--color=<when>auto, always, or never. Use always when you want color to survive a pipe.
-A, --show-allRender non-printable characters (tabs, carriage returns, the lot), like cat -A.

A worked example: you want line numbers but none of the rest, no pager, color forced on so it survives being piped into less -R yourself.

bash
bat --style=numbers --paging=never --color=always app.log | less -R

And the minimal "I just want the bytes with highlighting" form:

bash
bat -pp src/main.rs

-pp is --plain applied twice: the first disables decorations, the second disables paging. That is the form to use inside command substitutions or anywhere you want predictable output.

bat for git diffs and as a man pager

Two integrations are worth setting up once.

Highlight only the lines that changed in a Git working tree:

bash
bat --diff src/main.rs

That shows only the lines added, removed, or modified against the Git index, with syntax highlighting intact. Add --diff-context=<n> to include n surrounding lines. It is a quick way to eyeball "what did I touch here" without running git diff and losing syntax color.

Use bat as the pager for man, so man pages get color:

bash
export MANPAGER="sh -c 'col -bx | bat -l man -p'"

Drop that in your shell rc. col -bx strips the backspace-based bolding that man emits, and bat -l man -p renders it as a clean, colorized page. After that, man grep is a lot easier to read.

bat vs cat: when to use which

bat is a reading tool. cat is a plumbing tool. They overlap, but the line is clear once you have used both for a while.

catbat
HighlightingNoneSyntax-aware, themeable
Line numbers-n flag, plainOn by default, in a side column
Git changesNoneGutter markers in a repo
PagingNeverAuto (off in a pipe, off with --paging=never)
In a pipeRaw bytesRaw bytes (auto-detects, strips decoration)
AvailabilityEvery Unix box, no installNeeds installing
StartupInstantSlightly slower (loads syntax sets)

Use cat when you are concatenating files (cat a b c > out), feeding bytes into another program, or working on a minimal server where you cannot install anything. The name is literally short for "concatenate"; that is its real job and bat does not replace it there. Use bat when a human is reading a file and wants to actually see the structure: config files, source, logs, anything with syntax. For a long source file you are scanning, bat's pager and highlighting beat cat every time.

One honest caveat: bat is a bigger binary that loads syntax definitions on startup, so it is marginally slower than cat to first byte. You will never notice this reading one file. You might notice it if you call it in a tight loop over thousands of files, which is exactly the case where you should be using cat or a stream tool anyway.

See also

FAQ

Sources

Authoritative references this article was fact-checked against.

TagsbatcatCLISyntax HighlightingLinuxShell ScriptingRust

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts