cat Command in Linux: Complete Guide to File Concatenation, Display, and Parameters

cat command in Linux and it perimeters

cat command in Linux and it perimeters

cat was probably the second or third Linux command I ever learned, right after ls and cd, and for years I only ever used it to dump a file’s contents to the screen. It took a while before I realized it’s actually named for what it’s best at — concatenation — and that the “dump a file to screen” use case is really just a special case of joining zero or more files together and streaming the result. This guide covers the full breadth of cat: display, concatenation, file creation, all its display-control flags, and where it fits (and doesn’t fit) compared to less, more, and tac.

What Is the cat Command?

cat reads one or more files in sequence and writes their combined content to standard output. When given a single file, this looks like “displaying” the file; when given multiple files, it genuinely concatenates them. It’s part of GNU coreutils and is present on every Unix-like system by default.

Basic Syntax

cat [OPTION]... [FILE]...

If no FILE is given, or FILE is -, cat reads from standard input.

Basic Display

$ cat file1.txt
line1
line2
line3

Concatenating Multiple Files

This is the command’s namesake behavior:

$ cat file1.txt file2.txt
line1
line2
line3
line1
lineX
line3
line4

The output is simply file1’s content immediately followed by file2’s content — no separator is inserted automatically. This is exactly how you’d merge several log rotation files or split archive parts back into one stream:

$ cat part1.log part2.log part3.log > combined.log

Full Parameter Reference

OptionLong FormDescription
-n--numberNumber all output lines
-b--number-nonblankNumber only non-blank output lines
-s--squeeze-blankCollapse multiple consecutive blank lines into one
-A--show-allEquivalent to -vET — show tabs, line ends, and non-printing characters
-E--show-endsDisplay $ at the end of each line
-T--show-tabsDisplay tab characters as ^I
-v--show-nonprintingShow non-printing characters using ^ and M- notation
-eEquivalent to -vE
-tEquivalent to -vT
-uIgnored (kept for POSIX compatibility; unbuffered output is now the default)
--helpDisplay usage information
--versionShow version information

-n: Numbering Every Line

$ cat -n file1.txt
     1	line1
     2	line2
     3	line3

-b: Numbering Only Non-Blank Lines

This is genuinely useful when a file has intentional blank spacing you don’t want cluttering the line count:

$ printf 'a\n\n\n\nb\n' > blank.txt
$ cat -b blank.txt
     1	a



     2	b

Notice the blank lines are preserved but skipped in the numbering sequence.

-s: Squeezing Repeated Blank Lines

When a file has excessive blank-line padding — common in generated reports or poorly formatted exports — -s collapses runs of blank lines down to a single one:

$ cat -s blank.txt
a

b

-A: Showing Everything, Including Invisible Characters

This is the flag I reach for constantly when debugging whitespace issues — it makes tabs, line endings, and other non-printing characters visible:

$ cat -A tabfile.txt
col1^Icol2^Icol3$
foo^Ibar^Ibaz$

Here ^I represents a literal tab character and $ marks the actual end of each line. This immediately reveals things that are otherwise invisible on screen: trailing whitespace, Windows-style \r\n line endings (which would show as ^M$), and mixed tab/space indentation.

Reading from Standard Input

Without a file argument, cat reads from stdin, which makes it useful both as a genuine interactive tool and as a pipeline component:

$ cat
hello
hello
world
world

(Type a line, press Enter, and cat echoes it straight back — press Ctrl+D to end input.)

Creating Files with cat and Heredocs

A very common pattern is using cat with a heredoc to quickly create or append to a file without opening an editor:

$ cat >> file1.txt << 'EOF'
appended line
EOF
$ cat file1.txt
line1
line2
line3
appended line

Using >> appends; using > would overwrite the file entirely. The quoted 'EOF' delimiter prevents shell variable expansion inside the heredoc body — leave the quotes off if you actually want $VARIABLES expanded into the file content.

This pattern shows up constantly in provisioning scripts and Dockerfiles for writing small configuration files inline:

cat > /etc/myapp/config.yaml << 'EOF'
listen: 0.0.0.0:8080
log_level: info
EOF

How cat Works Internally

cat is one of the simplest programs on the system conceptually, but it’s a good example of how Linux I/O primitives fit together. For each file argument, cat:

  1. Opens the file with open().
  2. Reads chunks of data using read() into an internal buffer, sized to match the filesystem’s preferred I/O block size (queried via fstat()), which is typically 4KB or larger on modern systems.
  3. Writes each buffer straight to standard output using write().
  4. Closes the file with close() and moves to the next argument, if any.

When none of the formatting options (-n, -A, -s, etc.) are given, GNU cat takes a “fast path” — on Linux it can even use the sendfile() or copy_file_range() syscalls in some cases (depending on kernel and glibc versions) to move data directly between file descriptors without ever copying it through userspace buffers, cutting CPU overhead for very large files. As soon as any formatting flag is requested, cat has to actually inspect and transform the byte stream, so it falls back to the standard read/process/write loop.

This is a big part of why plain cat bigfile > /dev/null is often used informally as a crude I/O throughput test — it’s about as close to a raw byte-copy benchmark as a single command gets.

Real-World Use Cases

1. Quickly Inspecting a File

$ cat /etc/os-release

2. Merging Log Rotation Segments

$ cat app.log app.log.1 app.log.2 > full_history.log

3. Concatenating Split Archive Parts

Large files split with split are commonly reassembled with cat:

$ cat archive.tar.gz.part-* > archive.tar.gz

4. Feeding Multiple Config Fragments into a Single Pipeline

$ cat conf.d/*.conf | grep -v '^#' | sort

5. Quick File Creation in Scripts and Dockerfiles

$ cat > /tmp/motd << 'EOF'
Welcome to the staging environment.
EOF

6. Checking for Hidden Whitespace Bugs

$ cat -A suspicious_script.sh | grep -n '\^M'

This catches Windows line endings that can silently break shebang lines and shell scripts edited on Windows and transferred to Linux.

Shell Scripting and Automation

A practical example: normalizing a directory of files to strip carriage returns and squeeze blank lines, common when ingesting files exported from Windows-based systems:

#!/bin/bash
# clean_imports.sh - normalize line endings and blank lines in imported files
set -euo pipefail

IMPORT_DIR="${1:-./imports}"
OUT_DIR="${2:-./cleaned}"
mkdir -p "$OUT_DIR"

for f in "$IMPORT_DIR"/*.txt; do
    base=$(basename "$f")
    tr -d '\r' < "$f" | cat -s > "$OUT_DIR/$base"
    echo "Cleaned: $base"
done

Here tr -d '\r' strips carriage returns first (since cat itself has no option to remove them, only to display them), and cat -s squeezes any resulting blank-line runs.

cat vs Related Commands

CommandPurpose
catConcatenate and stream files to stdout; best for short files or piping
lessPaginated, interactive viewer for files too large to comfortably scroll past; supports search
moreOlder, simpler pager, mostly superseded by less
tacSame as cat but reverses line order (it’s literally “cat” spelled backward)
headShows only the first N lines of a file
tailShows only the last N lines, with -f for following live appends
nlDedicated line-numbering tool with more formatting control than cat -n
zcatLike cat, but transparently decompresses .gz files while streaming

The single most important practical distinction: don’t use cat on large files you intend to read interactively. cat somehugefile.log dumps everything at once with no pagination, no search, and no ability to jump around — that’s what less is for. A useful mental rule I follow: if I’m about to scroll, I should have used less; if I’m piping or genuinely need everything printed at once, cat is correct.

The Infamous “Useless Use of cat”

You’ll see this phrase a lot in Unix forums (referencing “UUOC”). It refers to patterns like:

$ cat file.txt | grep "pattern"

which works, but is unnecessary — grep can read a file directly:

$ grep "pattern" file.txt

This isn’t just pedantry; it avoids spawning an extra process and an extra pipe, which matters at scale (thousands of invocations in a loop) even though it’s invisible for a single interactive command. That said, using cat to concatenate multiple files into a single stream for grep is entirely legitimate and not a UUOC case:

$ cat file1.txt file2.txt | grep "pattern"

Troubleshooting Common Issues

Problem: cat file.txt shows garbled or binary-looking output. You’re likely cat-ing a binary file (executable, compressed archive, image). This can also mess up your terminal’s display state entirely, since raw binary bytes can include terminal control sequences. If your terminal starts behaving strangely afterward, run reset to restore it, and use file file.txt beforehand to check the file type before catting it blindly.

Problem: Trailing ^M characters appear with cat -A. This indicates Windows-style CRLF line endings. Strip them with tr -d '\r' < file.txt > file_unix.txt or dos2unix file.txt if available.

Problem: cat file.txt > file.txt produces an empty file. Same classic redirection-ordering gotcha as other tools — the shell truncates the output file before cat ever reads it. Never redirect a file’s output back into itself directly.

Problem: Concatenated files don’t have the separation you expected. cat never inserts newlines or separators between files — if file1.txt doesn’t end with a trailing newline, its last line and the first line of file2.txt will visually merge together on the same terminal line. Check with cat -A if the join looks wrong.

Performance Optimization

For simple display/concatenation without formatting flags, cat is about as efficient as it gets — potentially using zero-copy kernel syscalls as noted above. If you find yourself piping cat output into another tool that could read the file directly (cat file | sort vs sort file), prefer eliminating the extra process for scripts run at high frequency or scale. For genuinely large files, remember cat streams — it doesn’t load the whole file into memory — so memory usage stays flat regardless of file size; the practical performance limit is disk and pipe I/O throughput, not cat itself.

Security Implications

cat doesn’t execute file content, so displaying an untrusted file is safe from a code-execution standpoint. However, two things are worth knowing:

Compatibility Across Distributions

cat is part of GNU coreutils and ships identically across Ubuntu, Debian, Fedora, RHEL, Arch, and openSUSE. macOS and BSD systems ship a POSIX cat with a smaller flag set (no -A, -s, or -b in the strict BSD version, though macOS’s version does support some of these) — if writing cross-platform scripts, stick to POSIX-guaranteed flags (-n, -u) or test explicitly on the target platform.

Best Practices

Summary

cat is deceptively simple — read files, write them to stdout, in order — but that simplicity is exactly what makes it a foundational building block in shell pipelines, log management, quick file creation, and whitespace debugging. Knowing its full flag set (-n, -b, -s, -A, -E, -T) turns it from “the thing I dump files with” into a genuinely useful diagnostic and scripting tool, while knowing when not to use it (large interactive reads, unnecessary pipe chains) rounds out proper usage.

References

Exit mobile version