bat — A Better cat With Syntax Highlighting
Overview
bat is a cat-style file viewer with a nicer default UX:
- Syntax highlighting (auto-detect by filename / content)
- Line numbers, headers, and optional grid styling
- Pager integration (so large files don’t flood your terminal)
- Git integration (show changes inline in tracked files)
It’s ideal for reading WordPress configs, Nginx/Apache configs, shell scripts, and logs on a VPS—without losing your place.
- Core Function: Pretty-print files (or stdin) to stdout with optional paging.
- Primary Benefit: Faster comprehension of code/configs than plain
cat. - Where to Use: Reviewing scripts, debugging configs, inspecting logs, teaching snippets.
- Workflow:
bat [OPTIONS] [FILE...](or read from stdin).
Prerequisites
- Linux (Debian/Ubuntu, Fedora, Arch, etc.) or macOS
- Terminal access
- Some text/code files to view
System Check
On Debian/Ubuntu, the binary is often named batcat.
which bat || which batcat
Expected output:
/usr/bin/bat
# or on Debian/Ubuntu:
# /usr/bin/batcat
If your system uses batcat, you may want an alias for convenience:
alias bat=batcat
Install (common distros)
# Debian/Ubuntu
sudo apt install bat
# Fedora
sudo dnf install bat
# Arch
sudo pacman -S bat
# macOS (Homebrew)
brew install bat
bat in scriptsBy default, bat may page output and use color. In scripts and pipelines, prefer:
-p(plain, no decorations)--paging=never--color=never(if the next tool can’t handle ANSI colors)
Core Syntax
bat [OPTIONS] [FILE...]
FILE...: one or more files. If omitted,batreads from stdin.OPTIONS: control style (numbers/header/changes), theme, paging, color, ranges, and language.
Defaults you should know
- Syntax highlighting: auto-detected based on filename/content
- Paging: uses a pager when appropriate (prevents terminal flooding)
- Header: shows filename and a ruler by default
Options & Flags
| Option | What it does | When you’d use it | Example |
|---|---|---|---|
| : | : | :- | :-- |
-n, --number | Show line numbers | Debugging / code review | bat -n app.php |
--style=... | Control UI (header/grid/numbers/changes) | Reduce clutter or add context | bat --style=plain file |
--theme=... | Pick a theme | Improve readability | bat --theme=TwoDark file.py |
-A, --show-all | Show non-printing chars | Whitespace/CRLF debugging | bat -A Makefile |
-p, --plain | Plain output (no header/pager) | Script-friendly output | bat -p config.yml |
--paging=never/auto/always | Control paging behavior | Disable paging in pipelines | bat --paging=never file |
-l, --language=... | Force language syntax | Unknown extensions / stdin | bat -l php file |
-r, --line-range=... | Show specific line range(s) | Quick previews/snippets | bat -r 10:40 file |
--highlight-line=... | Highlight lines | Teaching/review emphasis | bat --highlight-line 42 file |
--color=always/auto/never | Control ANSI colors | Piping into other tools | bat --color=never file |
--diff | Show Git diff style for file | Review modified lines | bat --diff file |
--map-syntax ... | Map extension to language | Custom templates/types | bat --map-syntax .tpl:php |
- Interactive, readable:
bat -n --style=numbers,changes,header file - Minimal and script-safe:
bat -p --paging=never --color=never file
Common Patterns
- Interactive Viewing
- Script-Safe Output
- Snippets & Ranges
- Git-Aware Review
- WordPress VPS Use
bat /var/www/html/wp-config.php
bat -n /etc/nginx/sites-available/default
bat --theme=TwoDark --style=numbers,header /etc/hosts
bat -p --paging=never --color=never /etc/hosts
command_that_outputs_text | bat -p --paging=never --color=never
cat data.json | bat -l json -p --paging=never
bat -r 1:80 /var/www/html/wp-config.php
bat -r :50 --highlight-line 20,25 app.php
bat -r 120:160 --style=numbers,header /var/log/nginx/error.log
bat --diff src/main.py
diff -u old.conf new.conf | bat -l diff
bat -n /var/www/html/wp-config.php
bat -r :120 /etc/nginx/sites-available/default
tail -n 200 /var/log/nginx/error.log | bat --paging=never
Best Practices
-
Use
batinteractively for readability; switch to-pand--paging=neverin automation. -
If output is “too busy,” simplify style:
bat --style=plain file -
When debugging whitespace/indentation (Makefile/YAML), use:
bat -A file -
For files without extensions or stdin, force language:
bat -l bash script -
If you want
batas acatreplacement, do it only for interactive shells:- Good idea: alias
cat=batin your shell profile - Bad idea: relying on that alias inside scripts
- Good idea: alias
bat vs cat vs nano — what to use and when?
cat: Fast, minimal, ubiquitous. Great for quick dumps, combining files, and pipelines. No highlighting.bat: Likecat, but optimized for humans—highlighting, numbers, paging, Git changes.nano: Editor. Use it when you need to modify content, not just view it.
Rule of thumb
- Viewing code/configs/logs:
bat - Simple piping/compatibility:
cat - Editing:
nano
Troubleshooting
| Problem | Likely Cause | Fix |
|---|---|---|
| :-- | :- | :- |
| No colors | Output is piped / non-TTY | Use --color=always (interactive) or avoid piping |
| Pager appears when you don’t want it | Default paging behavior | Add --paging=never or use -p |
| No syntax highlighting | Unknown extension | Use -l <lang> or --map-syntax |
| Output feels too “busy” | Header/grid/numbers/changes enabled | Use --style=plain or --style=numbers |
bat not found on Debian/Ubuntu | Binary is batcat | Use batcat or alias bat=batcat |
If you pipe bat output into tools that don’t expect ANSI codes (or into files), use --color=never to avoid escape sequences in saved output.
Cheat Sheet
# Basics
bat file.txt # Highlighted file with header and pager
bat -n file.php # Show line numbers
bat -A Makefile # Show all characters (tabs, EOLs)
# Styles, themes, and paging
bat --style=numbers,changes file.js # Custom style
bat --theme=TwoDark file.py # Use specific theme
bat --paging=never file.log # Disable paging
bat -p config.yml # Plain mode (no header, no pager)
# Ranges and highlighting
bat -r 10:40 app.php # Only lines 10–40
bat --highlight-line 42 app.php # Highlight line 42
bat -r :50 --highlight-line 20,25 app.php # First 50 lines, highlight some
# Language and stdin
bat -l json settings # Force JSON highlighting
cat data.json | bat -l json # Pretty-print JSON from stdin
# Git changes
bat --diff src/main.py # Show changed lines with diff style
Mini Quiz
- Which option controls the presence of headers, numbers, and other UI elements?
- How do you disable the pager for scripts/pipelines?
- How do you show non-printing characters like tabs and end-of-line markers?
- What do you use when
batguesses the wrong language? - How do you show only lines 100–150 of a file?
Show answers
--style=...--paging=never(and/or-p)-A/--show-all-l <language>(or--map-syntax ...)-r 100:150 file
Worked Examples
Output below is shown without colors. In a real terminal, syntax highlighting and UI decorations will be colored depending on theme and terminal capabilities.
Example files used in demos
Assume we have app.php:
<?php
echo "Hello, world!\n";
$version = "1.0.0";
if ($version === "1.0.0") {
echo "Stable\n";
}
And a script file named script (no extension):
#!/bin/bash
echo "Backup started"
1) Basic view of a file
bat app.php
Expected output (simplified):
───────┬────────────────────────────────────────────
│ File: app.php
───────┼────────────────────────────────────────────
1 │ <?php
2 │ echo "Hello, world!\n";
3 │ $version = "1.0.0";
4 │ if ($version === "1.0.0") {
5 │ echo "Stable\n";
6 │ }
───────┴────────────────────────────────────────────
2) Show line numbers explicitly
bat -n app.php
Expected output:
───────┬────────────────────────────────────────────
│ File: app.php
───────┼────────────────────────────────────────────
1 │ <?php
2 │ echo "Hello, world!\n";
3 │ $version = "1.0.0";
4 │ if ($version === "1.0.0") {
5 │ echo "Stable\n";
6 │ }
───────┴────────────────────────────────────────────
3) Plain mode (no header, no pager, no decorations)
bat -p app.php
Expected output:
<?php
echo "Hello, world!\n";
$version = "1.0.0";
if ($version === "1.0.0") {
echo "Stable\n";
}
4) Show all characters (tabs/EOL markers)
bat -A app.php
Expected output (illustrative):
───────┬────────────────────────────────────────────
│ File: app.php
───────┼────────────────────────────────────────────
1 │ <?php␊
2 │ echo·"Hello,·world!\n";␊
3 │ $version·=·"1.0.0";␊
4 │ if·($version·===·"1.0.0")·{␊
5 │ ······echo·"Stable\n";␊
6 │ }␊
───────┴────────────────────────────────────────────
5) Show only a line range (lines 2–4)
bat -r 2:4 app.php
Expected output:
───────┬────────────────────────────────────────────
│ File: app.php
───────┼────────────────────────────────────────────
2 │ echo "Hello, world!\n";
3 │ $version = "1.0.0";
4 │ if ($version === "1.0.0") {
───────┴────────────────────────────────────────────
6) Highlight a specific line
bat --highlight-line 3 app.php
Expected output (line highlighted; shown here with >>):
───────┬────────────────────────────────────────────
│ File: app.php
───────┼────────────────────────────────────────────
1 │ <?php
2 │ echo "Hello, world!\n";
>> 3 │ $version = "1.0.0";
4 │ if ($version === "1.0.0") {
5 │ echo "Stable\n";
6 │ }
───────┴────────────────────────────────────────────
7) Use a specific theme
bat --theme=TwoDark app.php
Expected output: (same structure; colors differ based on theme)
───────┬────────────────────────────────────────────
│ File: app.php (theme: TwoDark)
───────┼────────────────────────────────────────────
1 │ <?php
2 │ echo "Hello, world!\n";
3 │ $version = "1.0.0";
4 │ if ($version === "1.0.0") {
5 │ echo "Stable\n";
6 │ }
───────┴────────────────────────────────────────────
8) Force language for a file without extension
bat -l bash script
Expected output:
───────┬────────────────────────────────────────────
│ File: script (language: Bash)
───────┼────────────────────────────────────────────
1 │ #!/bin/bash
2 │ echo "Backup started"
───────┴────────────────────────────────────────────
9) View configuration without pager (pipeline/script safe)
bat --paging=never -p /etc/hosts
Expected output (simplified):
127.0.0.1 localhost
127.0.1.1 my-vps
# IPv6 entries...
::1 localhost ip6-localhost ip6-loopback
10) Pretty-print JSON from stdin
cat data.json | bat -l json
Expected output (simplified):
───────┬────────────────────────────────────────────
│ STDIN (language: JSON)
───────┼────────────────────────────────────────────
1 │ {
2 │ "name": "site",
3 │ "enabled": true
4 │ }
───────┴────────────────────────────────────────────
11) Show only the top of a large log file (first 50 lines)
bat -r :50 /var/log/nginx/access.log
Expected output: (first 50 lines shown; truncated here)
───────┬────────────────────────────────────────────
│ File: /var/log/nginx/access.log
───────┼────────────────────────────────────────────
1 │ 192.168.0.10 - - [12/Nov/2025:10:00:01 +0000] "GET / HTTP/1.1" 200 512 "-" "curl/7.81.0"
2 │ 192.168.0.11 - - [12/Nov/2025:10:00:02 +0000] "GET /favicon.ico HTTP/1.1" 404 162 "-" "curl/7.81.0"
3 │ ...
50 │ ... (line 50)
───────┴────────────────────────────────────────────
12) Show Git changes inline
bat --diff src/main.py
Expected output (illustrative markers):
───────┬────────────────────────────────────────────
│ File: src/main.py
───────┼────────────────────────────────────────────
1 │ import sys
- 2 │ old_line = "this used to be here"
+ 2 │ new_line = "this line changed"
3 │ print(new_line)
───────┴────────────────────────────────────────────
13) Customize style to show only numbers and code
bat --style=numbers app.php
Expected output:
1 <?php
2 echo "Hello, world!\n";
3 $version = "1.0.0";
4 if ($version === "1.0.0") {
5 echo "Stable\n";
6 }
14) Use bat in a pipeline (disable paging)
ps aux | bat --paging=never
Expected output (first lines):
───────┬────────────────────────────────────────────
│ STDIN
───────┼────────────────────────────────────────────
1 │ USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
2 │ root 1 0.0 0.1 169340 9300 ? Ss 10:00 0:02 /sbin/init
3 │ www-data 1234 0.1 1.2 523456 48200 ? S 10:01 0:10 php-fpm: pool www
4 │ ...
───────┴────────────────────────────────────────────
15) View a unified diff with syntax highlighting
diff -u old.conf new.conf | bat -l diff
Expected output:
───────┬────────────────────────────────────────────
│ STDIN (language: diff)
───────┼────────────────────────────────────────────
1 │ old.conf
2 │ +++ new.conf
3 │ @@ -1,3 +1,3 @@
4 │ -max_clients = 50
5 │ +max_clients = 100
6 │ timeout = 30
───────┴────────────────────────────────────────────