# bat: the cat clone that quietly becomes cat the moment you pipe it

> Syntax highlighting, a git sidebar and automatic paging make bat a better terminal reader, and one deliberate behaviour makes it safe in scripts: the moment output is not a terminal, every feature turns off. The library path is a separate story, with a different feature set and the syntaxes and themes left out of the published crate.

**sharkdp/bat** — A cat(1) clone with wings. If you are looking for more support for git and diff operations, check out delta.

- Repository: https://github.com/sharkdp/bat
- Stars: 60,575 · Forks: 2,442
- Language: Rust
- License: Apache-2.0
- Published: 2026-08-08 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/sharkdp-bat

## Piping into anything silently drops every feature

Here is the behaviour that makes bat safe, and it is worth knowing before it surprises you. Whenever bat detects a non-interactive terminal, meaning you have piped into another process or redirected into a file, it acts as a drop-in replacement for cat and falls back to printing plain file contents, regardless of the value of the `--pager` option.

The consequence is that `bat main.rs | xclip` gives you the file and nothing else. No highlighting, no line numbers, no git sidebar, and no error saying so. That is exactly why the README documents `-p`/`--plain` for the cases where you need plain output on a terminal, and notes that bat detects redirection and prints plain contents on its own. The behaviour is correct and the same sentence explains why copying a file out of bat is hard, since line numbers and git modification markers get in the way of a clean paste.

The related case is a live log, where the degradation is not enough on its own:

```bash
tail -f /var/log/pacman.log | bat --paging=never -l log
```

Two flags are needed and for two different reasons. Paging has to be switched off explicitly for the combination to work, and the language has to be given with `-l log` because it cannot be auto-detected in this case. The auto-detection story is the other half of this: reading from stdin works, but only when the syntax can be determined from the first line, usually through a shebang, which is why `curl -s https://sh.rustup.rs | bat` highlights and a pipe of arbitrary text may not.

## As a library, bat is a different build from the binary

The Cargo.toml is unusually explicit about this, and anyone embedding bat will hit it. The default feature set is `application` and `git`. The `application` feature is annotated as required for bat the application and something that should be disabled when depending on bat as a library, and it pulls in `bugreport`, `build-assets` and `minimal-application`. That last one is annotated as mainly for developers who want to iterate quickly, with a warning that the included features might change in the future.

Two more choices are forced on you. You need one of `regex-onig`, which selects the oniguruma regex engine, or `regex-fancy`, the Rust-only fancy-regex engine, and the comment says plainly that you need one of these if you depend on bat as a library. Separately, `git = ["gix"]` is how the git modification sidebar is wired in, through the gix crate, so a library consumer who wants the sidebar has to ask for that feature.

The consequence is that a library integration is a real configuration task with three decisions in it, and one of the feature groups involved is explicitly labelled unstable. The repository does ship library examples, including `simple.rs`, `advanced.rs`, `inputs.rs`, `buffer.rs` and one called `list_syntaxes_and_themes.rs`, which is the right place to start.

## The crate excludes the syntaxes and themes it highlights with

The `exclude` field in Cargo.toml lists `assets/syntaxes/*` and `assets/themes/*`. Those are not build artefacts or test fixtures. They are the syntax definitions and the colour themes, and they are exactly what makes bat look the way it does.

Read alongside the feature flags, this produces a specific and slightly awkward situation. Highlighting is implemented with syntect, and the `build-assets` feature pulls in syntect's yaml-load and plist-load capabilities plus regex and walkdir, so the machinery to load syntaxes is compiled in. What is not shipped in the published package is the syntax and theme content itself. A binary installed from a release has them; a crate pulled from a registry may not.

The consequence is that if you embed bat as a library you should find out early where your syntax definitions are going to come from, because the crate will not supply them and the README does not discuss the gap. It is also the reason the syntaxes live under an `assets/` directory in the repository with a git submodule configuration alongside it, rather than being generated at build time.

## Git integration is a sidebar against the index, and diff is somebody else's job

The git feature does one specific thing: bat communicates with git to show modifications with respect to the index, rendered as a left sidebar. That is a narrow, well-chosen feature rather than a general git integration, and it depends on the `gix` crate being enabled.

Diff support exists in a limited form. You can pass `--diff`, and the README gives a shell function that wires it to git:

```bash
batdiff() {
    git diff --name-only --relative --diff-filter=d -z | xargs -0 bat --diff
}
```

Then it tells you what to do with that if you want it as a real tool, pointing at `batdiff` in the bat-extras repository, and immediately follows with the sentence that settles the scope: if you are looking for more support for git and diff operations, check out delta.

The consequence is that the project author considers diff somebody else's specialism, and the project's own description carries the same redirect in its one-line summary. This is a file reader with a version-control annotation, not a diff tool. If diff is what you want, the README is sending you to delta and you should not spend time assembling bat's version.

## Paging is the one default that differs from cat

By default bat pipes its own output to a pager, less being the example given, when the output is too large for one screen. cat never does this. If you want cat's behaviour, the README gives you the option and then the alias, in that order, because the alias is only safe once the option is understood:

If you intend to alias cat to bat in your shell configuration, use `alias cat='bat --paging=never'` to preserve the default behaviour. You can set `--paging=never` on the command line or in the configuration file.

The consequence is that `alias cat='bat'` is the version that surprises people, because it changes the paging behaviour of every command in the shell at once. The README's own advice is the careful one, and the order of those two sentences is a hint that the author has seen this go wrong. File concatenation is the other place the two tools differ in a way that matters: even with a pager set, bat can still be used to concatenate files, which is what makes `bat header.md content.md footer.md > document.md` work.

## The man page syntax is the project's own unfinished work

The most popular integration in the file is `man`. You set the `MANPAGER` environment variable to use bat as a colourising pager:

```bash
export MANPAGER="bat -plman"
man 2 select
```

Two caveats come with it. On some older Debian and Ubuntu releases the executable is named `batcat` rather than `bat`, which breaks the export on exactly the distributions where a manual pager is most wanted. And the README attaches a note to the syntax definition itself, saying that the manpage syntax, which lives in this repository at `assets/syntaxes/02_Extra/Manpage.sublime-syntax`, is developed here and still needs some work.

The consequence is that the integration whose output you look at most often is the one with a self-declared incomplete highlighter, and the fix is a separate project: if you would rather have it bundled as a new command, the README points at `batman` in bat-extras. That is the pattern across this whole section, incidentally. fzf previews, batgrep for ripgrep, prettybat for formatters and the help wrappers all live in bat-extras, and the ones in the core README are the ones implemented in bat itself.

## Rust 1.88 is the floor, and the project says it may move

The package declares `rust-version = "1.88"` and edition 2021, with a comment attached that is unusual enough to quote: you are free to bump MSRV as soon as a reason for bumping emerges. In other words, the minimum supported Rust version is explicitly not a stability guarantee. It can move in a patch release of bat.

The licensing is also worth reading carefully rather than from the badge. GitHub's classification for the repository is Apache-2.0, while Cargo.toml states the licence as `MIT OR Apache-2.0`, and the tree carries `LICENSE-APACHE`, `LICENSE-MIT` and a `NOTICE` file, which is the standard set for a dual licence. The package version is 0.26.1.

The consequence for distribution is that your build can break on a bat upgrade for a reason unrelated to anything you use, which matters if you vendor binaries. And the dual licence is the permissive one, so a distributor can pick either; the metadata discrepancy is cosmetic but is the kind of thing that trips automated compliance scanners, which read the repository classification rather than the manifest.

## Conclusion

bat is one of the few replacements for a core Unix tool that is worth the switch, and the reason is not the highlighting. It is that the author treated compatibility as a feature rather than an accident, documenting exactly when the tool degrades to plain cat and giving you the flags to restore each behaviour deliberately. The trade is that a pipe is a downgrade you did not ask for, and the git sidebar in particular is unavailable in any script. Two other limits are worth knowing. As a library, bat is a different product from the binary, with a feature set you must choose and assets that are not in the crate. And the project itself points elsewhere for diff work, so bat is a file reader rather than a diff tool. Before standardising it, check three things: whether any of your pipelines depend on the decorated output, whether your minimum Rust version matches the declared 1.88 floor, and whether the crates.io version you pin includes the git sidebar, since that is a cargo feature rather than a default in the library build.

## FAQ

### What is the bat command in Linux and what is it used for?

bat is a cat(1) clone written in Rust that adds syntax highlighting for many programming and markup languages, a sidebar showing modifications with respect to the git index, highlighting of non-printable characters with `-A`/`--show-all`, and automatic paging when output exceeds a screen. It also works as a man page pager through MANPAGER and as a previewer for tools like fzf.

### What is the difference between the bat and cat commands in Linux?

bat adds syntax highlighting, line numbers, a git modification sidebar and automatic paging. Two differences matter for scripting: whenever bat detects a non-interactive terminal it falls back to printing plain contents regardless of the `--pager` option, and paging is on by default, which you disable with `--paging=never`, for example via `alias cat='bat --paging=never'`.

### How do I install bat on macOS?

The project is published on crates.io as bat and the README carries a dedicated Installation section, alongside Chinese, Japanese, Korean and Russian translations. Building from source needs a recent toolchain, since the manifest declares edition 2021 and a minimum supported Rust version of 1.88, and notes that this floor may be bumped.

## Sources

- [Official README](https://github.com/sharkdp/bat#readme)
- [Project repository](https://github.com/sharkdp/bat)
- [Release notes](https://github.com/sharkdp/bat/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/sharkdp-bat
