If you’ve spent even ten minutes on a Linux terminal, you’ve probably already typed cat without thinking twice about it. It’s one of the first commands anyone learns, right alongside ls and cd. But here’s the thing — most people only ever scratch the surface of what cat can actually do. I want to walk you through this command the way I wish someone had explained it to me years ago: starting from the absolute basics, then digging into the internals, the edge cases, the scripting tricks, and the situations where cat is either the perfect tool or exactly the wrong one.
By the end of this guide, you’ll understand not just how to use cat, but why it behaves the way it does, and when you should reach for something else instead.
What Is the cat Command?
cat stands for “concatenate.” That name is the whole story of the command — it was originally built to join multiple files together and print the result. Over time, because it’s so simple and fast, people started using it for all sorts of things: viewing file contents, creating small files, feeding data into pipelines, and combining streams of text.
cat is part of the GNU coreutils package on most Linux distributions, which means it ships by default on virtually every system you’ll ever touch — Ubuntu, Debian, Fedora, Arch, CentOS, you name it. You can confirm the version installed on your machine with:
cat --version
On my test system this returns:
cat (GNU coreutils) 9.4
That single line tells you two things: you’re running the GNU implementation (as opposed to the BSD version found on macOS or some BSD-based systems), and you know exactly which feature set you have access to.
Basic Syntax
The general syntax looks like this:
cat [OPTIONS] [FILE...]
If you don’t pass any file, cat reads from standard input instead, which is why it’s so often used in pipelines. If you pass multiple files, it concatenates them in the order given and prints the result to standard output.
Viewing a File’s Contents
The simplest and most common use case is just dumping a file to your terminal:
cat test1.txt
Output:
line1
line2
line3
No formatting, no pagination, no line wrapping logic — it just prints everything straight through. That’s both cat‘s biggest strength and its biggest limitation. For small config files or short scripts, this is perfect. For a 10,000-line log file, it’s going to scroll your terminal into oblivion, and you’ll want less or more instead (more on that comparison later).
Concatenating Multiple Files
This is the feature the command is named after. Say you have two files:
printf "line1\nline2\nline3\n" > test1.txt
printf "lineA\nlineB\n" > test2.txt
Running:
cat test1.txt test2.txt
produces:
line1
line2
line3
lineA
lineB
The files are joined in the exact order you list them, with no separator inserted between them beyond whatever line endings already exist in the files. This is genuinely useful when you’re combining log fragments, joining CSV parts, or assembling a multi-part script.
You can also redirect that combined output into a brand-new file:
cat test1.txt test2.txt > combined.txt
Or append it to an existing file using >> instead of >:
cat test1.txt >> test2.txt
This appends the entire content of test1.txt onto the end of test2.txt. Be careful with the direction of your arrows here — a single > overwrites the destination file completely, while >> preserves what’s already there and adds to it. I’ve seen people wipe out important files by fat-fingering > when they meant >>, so this is worth internalizing early.
Numbering Lines with -n and -b
When you’re debugging a script or referencing specific lines in a file, line numbers are incredibly useful.
cat -n test1.txt
Output:
1 line1
2 line2
3 line3
Notice the numbers are right-aligned and followed by a tab character before the actual content.
The -b flag is a close cousin, but it only numbers non-blank lines:
printf "a\n\nb\n" > blanktest.txt
cat -b blanktest.txt
Output:
1 a
2 b
Notice how the blank line in the middle is left unnumbered, while a and b get numbers 1 and 2 respectively. This is handy when you’re counting actual content lines and don’t want blank spacing to throw off your numbering.
Squeezing Blank Lines with -s
Sometimes a file has excessive blank lines — maybe from a badly formatted export or repeated appends — and you want to compress consecutive blank lines down to a single one without editing the file itself.
printf "a\n\n\n\nb\n" > squeezetest.txt
cat -s squeezetest.txt
Output:
a
b
Even though the original file had three blank lines between a and b, cat -s collapses them into just one for display purposes. Note this doesn’t modify the file — it only changes what gets printed.
Showing Non-Printing Characters with -A, -E, -T
This is where cat becomes a genuinely useful debugging tool, especially when you’re chasing down invisible whitespace issues, mixed line endings, or files that “look” fine but behave oddly.
-A (equivalent to -vet) shows tabs as ^I, line endings as $, and other non-printing characters using caret notation:
printf "a\tb\n" > tabtest.txt
cat -A tabtest.txt
Output:
a^Ib$
That ^I is the tab character, and the $ marks the end of the line. This is invaluable when you suspect a file has trailing whitespace or when you’re troubleshooting a script that mysteriously fails because someone used tabs where spaces were expected (or vice versa — looking at you, Makefiles and YAML).
-E shows only line endings:
cat -E test1.txt
Output:
line1$
line2$
line3$
-T shows only tabs:
cat -T tabtest.txt
Output:
a^Ib
These flags are particularly useful when comparing files that were edited on Windows versus Linux, since Windows line endings (\r\n) will show up as ^M$ under -A, revealing the classic carriage-return issue that breaks shell scripts.
Creating Files with cat and Heredocs
You don’t need a text editor for quick file creation. cat combined with a heredoc is a fast way to generate small files, especially inside shell scripts:
cat > heredoctest.txt << "EOF"
Hello World
Second line
EOF
Running cat heredoctest.txt afterward confirms:
Hello World
Second line
Quoting the delimiter ("EOF" instead of EOF) prevents variable expansion inside the heredoc, which matters if your content contains $ characters you don’t want interpreted. This trick shows up constantly in installation scripts, Dockerfiles, and CI/CD pipelines where you need to generate a config file on the fly.
You can also type content directly without a heredoc:
cat > quicknote.txt
After running this, cat waits for your input. Type your text, then press Ctrl+D on a new line to signal end-of-file and save. This is essentially using cat as a minimalist text editor, and it’s genuinely handy for jotting quick notes over SSH when you don’t want to bother with nano or vim.
How cat Works Internally
Under the hood, cat is deceptively simple. It opens each file argument (or reads from stdin if none is given), reads the raw bytes in chunks, and writes those bytes directly to standard output using low-level system calls like read() and write(). There’s no line-by-line parsing happening unless you use flags like -n or -A, which require it to inspect content more closely.
This design is exactly why cat is so fast — it’s essentially just moving bytes from one file descriptor to another with minimal processing overhead. GNU cat even has an internal optimization path that, when none of the formatting options are used, can use larger buffer sizes and avoid unnecessary character-by-character logic entirely.
This matters for performance: cat largefile.log > /dev/null is a legitimate (if crude) way to benchmark raw disk read throughput, since the command does almost nothing except read and immediately discard.
cat with Standard Input and Pipes
cat shines in pipelines. Since it reads stdin when no file is specified, you can chain it with other commands:
echo "some text" | cat
Output:
some text
That example is trivial, but the real value shows up when cat sits in the middle of a longer pipeline, feeding file content into filters:
cat access.log | grep "404" | wc -l
This counts how many lines in a log file contain “404” errors. Seasoned Linux users will point out — correctly — that this is technically an “unnecessary use of cat,” since grep can read files directly:
grep "404" access.log | wc -l
Both produce identical results, but the second version skips spawning an extra process. This is a well-known nitpick in the Linux community, sometimes jokingly called “Useless Use of Cat” (UUOC). It’s not going to break anything, but if you’re writing scripts that run thousands of times, cutting unnecessary cat calls can shave off real overhead.
Reversing Output with tac
Since I mentioned cat‘s name means “concatenate,” it’s worth noting its cheeky companion command: tac, which is cat spelled backward and does exactly what you’d guess — prints file content with the lines in reverse order.
tac test1.txt
Output:
line3
line2
line1
This is a small but genuinely useful utility when you need to read the most recent entries of a log file first without them scrolling past you.
cat vs less vs more vs head vs tail
This is where a lot of newcomers get confused, so let me lay out the practical differences clearly.
catdumps the entire file at once with no pagination. Best for small files or piping into other commands.lessopens an interactive pager that lets you scroll, search, and navigate large files without loading the whole thing into your terminal buffer at once. Useless bigfile.logfor anything sizable.moreis an older, more limited pager — mostly superseded byless, though it still exists for compatibility.headshows just the first N lines of a file (default 10):head -n 20 file.txt.tailshows just the last N lines, and with-fit follows a file in real time, which is essential for watching live logs:tail -f /var/log/syslog.
A good rule of thumb: use cat when you want everything, right now, no interaction needed. Use less when the file is large and you want to explore it. Use head/tail when you only care about one end of the file.
Real-World System Administration Use Cases
In actual day-to-day sysadmin work, cat shows up constantly:
Checking system information quickly:
cat /etc/os-release
This prints distribution details straight from the file — useful when writing scripts that need to behave differently depending on OS:
PRETTY_NAME="Ubuntu 24.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
Reading kernel version:
cat /proc/version
Checking boot parameters:
cat /proc/cmdline
Combining configuration snippets before deployment:
cat base.conf environment-prod.conf > final.conf
Quickly viewing a script before executing it (never skip this step with downloaded scripts):
cat install.sh
Verifying SSH public keys before adding them to authorized_keys:
cat id_rsa.pub >> ~/.ssh/authorized_keys
That last one is a classic sysadmin move for setting up passwordless SSH access, and it’s a perfect example of cat‘s append behavior being exactly what you want.
Shell Scripting with cat
Inside scripts, cat is often used to read config values or generate output dynamically:
#!/bin/bash
CONFIG=$(cat /etc/myapp/config.txt)
echo "Loaded config: $CONFIG"
Or to build a file conditionally:
#!/bin/bash
if [ "$ENVIRONMENT" = "production" ]; then
cat > /etc/myapp/settings.conf << EOF
mode=production
debug=false
EOF
else
cat > /etc/myapp/settings.conf << EOF
mode=development
debug=true
EOF
fi
This pattern of using heredocs with cat to template out configuration files is extremely common in provisioning scripts, Ansible playbooks (via shell modules), and Docker entrypoint scripts.
Common Troubleshooting Scenarios
“cat: file: No such file or directory” — This means the path is wrong or the file genuinely doesn’t exist. Double-check your working directory with pwd and list contents with ls before assuming the file is missing.
“cat: file: Permission denied” — You don’t have read permissions on the file. Check with ls -l file and either adjust permissions with chmod (if you own it) or use sudo cat file (carefully, since running commands as root should always be deliberate, not habitual).
Terminal fills with garbage characters after catting a binary file — This happens because cat doesn’t know or care whether a file is text or binary; it just writes raw bytes to your terminal, and binary data often includes control characters that mess with your terminal’s display state. If this happens, type reset and press Enter (even if you can’t see what you’re typing) to restore your terminal to a sane state.
Output looks fine in the file but breaks a script — This usually points to invisible characters like carriage returns from Windows-edited files. Run cat -A file to reveal hidden ^M characters, then strip them with dos2unix file or sed -i 's/\r$//' file.
Performance and Security Considerations
From a performance standpoint, cat is about as lightweight as commands get, but there are a couple of things worth knowing. Concatenating many very large files with cat will use whatever memory the OS allocates for I/O buffering, but it doesn’t load entire files into memory at once — it streams them, so even huge files won’t crash your system from a memory perspective. Disk I/O and terminal rendering speed are usually your real bottlenecks, not cat itself.
On the security side, be cautious with cat on files you don’t control, especially when running as root. Since cat prints exactly what’s in a file, catting a file with embedded terminal escape sequences can theoretically manipulate your terminal display in unexpected (if usually harmless) ways. This is a minor and rarely exploited risk, but it’s part of why security-conscious admins avoid blindly catting untrusted files, especially ones downloaded from the internet, without inspecting them first with something safer like less or a hex viewer (xxd or hexdump).
Also worth remembering: cat respects file permissions like any other program. It cannot read a file you don’t have permission to read, regardless of any flags you pass — permission enforcement happens at the kernel level, not inside cat itself.
Compatibility Across Distributions
The GNU version of cat described in this guide ships by default on Ubuntu, Debian, Fedora, RHEL, CentOS, Arch Linux, and basically every mainstream Linux distribution, since they all rely on GNU coreutils. The flags and behavior described here will work identically across all of them.
If you ever work on a BSD system, macOS, or a minimal container image using BusyBox, be aware that cat there may support a smaller subset of flags. BusyBox’s cat, for instance, typically only understands -n and a couple of others, so scripts relying on GNU-specific flags like -A or -s may fail silently or throw an “invalid option” error on those systems. If you’re writing portable shell scripts meant to run across different environments, it’s worth checking cat --help on the target system first.
Summary
cat looks like the simplest command in your toolbox, and in a sense it is — but that simplicity is exactly what makes it so versatile. It reads files, joins them, numbers their lines, reveals hidden characters, creates new files through heredocs, and slots effortlessly into pipelines with other tools. Once you understand its full option set and know when to reach for less, tail, or grep instead, you’ll find yourself using cat more deliberately and more effectively.
It’s a small command, but it’s also a perfect example of the Unix philosophy: do one thing, do it well, and let it compose cleanly with everything else on the system.
References
- GNU Coreutils Manual —
cat: https://www.gnu.org/software/coreutils/manual/html_node/cat-invocation.html - Linux man-pages project,
cat(1): https://man7.org/linux/man-pages/man1/cat.1.html - GNU Project documentation: https://www.gnu.org/software/coreutils/