DEV Community

Cover image for Stop Using cat for Everything: 9 Better Ways to Read Linux Files
Asep Sayyad
Asep Sayyad

Posted on Edited on Originally published at asepsayyad007.in

Stop Using cat for Everything: 9 Better Ways to Read Linux Files

Practical tools to inspect, page, slice, and debug files without freezing your terminal

Running cat /var/log/nginx/access.log on an active server is an unforced error that most engineers make once before watching their shell lock up.

The utility name is short, muscle memory takes over, and the binary exists on every Unix host in existence. But cat stands for concatenate. Its original Unix design was to join multiple input streams together and ship the output down a pipeline. It was never built as an interactive file viewer.

When you use cat to inspect files interactively, you offload stream buffering directly to your terminal emulator. If that file happens to be a multi-gigabyte JSON log or an active audit trail, your terminal tries to process, parse, and render millions of lines into its local scrollback window. Your terminal emulator consumes gigabytes of memory, remote SSH sessions drop keystrokes, stray escape sequences scramble font settings, and you have zero ability to pause, scroll, or search inline.

Linux comes with specialized utilities built to inspect, page, slice, reformat, and navigate files without wasting system resources or locking your session.

Here are nine better ways to read files on Linux, along with the exact flags to use in production.


1. bat: Syntax Highlighting, Git Awareness, and Smart Paging

If you want to view a configuration file, shell script, or source code file directly on stdout without opening an interactive viewer, bat is the modern replacement for cat.

On Debian and Ubuntu distributions, the package is installed as batcat to prevent name clashes with another system binary:

sudo apt-get install bat
alias bat="batcat"
Enter fullscreen mode Exit fullscreen mode

Unlike raw cat, bat inspects file extensions and shebang lines to apply high-contrast syntax highlighting across hundreds of languages. It renders line numbers automatically and integrates directly with Git to show added, modified, and removed lines directly in the left gutter.

To view an Nginx configuration with line numbers and syntax highlighting:

bat /etc/nginx/nginx.conf
Enter fullscreen mode Exit fullscreen mode

One of the best features in bat is automatic smart paging. If the target file fits within the height of your terminal screen, bat writes the output straight to stdout and drops you back at your shell prompt. If the output exceeds your terminal height, it routes the stream through an interactive pager automatically.

You can also use bat to expose non-printable control characters, trailing spaces, and hidden carriage returns:

bat -A /etc/environment
Enter fullscreen mode Exit fullscreen mode

The -A flag displays tab stops as arrows, spaces as subtle dots, and newlines as explicit symbols, making syntax debugging straightforward.


2. less with -FXRS: Zero-Memory Paging and Instant Regex Search

When a file exceeds a few megabytes, printing it straight to stdout is risky. The less pager remains the industry benchmark for high-performance file viewing because it does not load the entire file into RAM before displaying it.

less uses memory mapping (mmap) to read only the small slice of bytes needed to fill your current terminal dimensions. You can open a 50GB database dump or a massive systemd log instantaneously without causing memory pressure or disk thrashing on the host:

less -FXRS /var/log/syslog
Enter fullscreen mode Exit fullscreen mode

The four flags combined here make less behave cleanly for system administration:

  • -F tells less to exit immediately if the entire file fits on a single terminal screen.
  • -X stops less from sending the terminal initialization strings that clear the screen on exit, leaving the inspected lines visible in your terminal scrollback.
  • -R processes raw ANSI color escape codes properly, ensuring colored log output from modern CLI tools renders correctly instead of displaying garbled control sequences.
  • -S disables line wrapping. Long log lines are truncated horizontally instead of wrapping into messy multi-line blocks. You can pan horizontally using the left and right arrow keys to inspect wide timestamps and JSON structures.

Inside less, you navigate quickly using single keystrokes:

  • Press G to jump straight to the end of the file.
  • Press g to return to the first line.
  • Type / followed by a search pattern to search forward using regular expressions.
  • Type ? followed by a search pattern to search backward through previous entries.
  • Press n to jump to the next search match, or N to jump to the previous match.
  • Press +F to enter follow mode, which updates the view in real time as new lines append to the file, identical to tail -f. Pressing Ctrl+C drops you back into scrollable, searchable mode without closing the file.

You can set these flags permanently by adding this export to your shell configuration (~/.bashrc or ~/.zshrc):

export LESS="-FXRS"
export PAGER="less"
Enter fullscreen mode Exit fullscreen mode

3. tail -F and head: Slicing Boundaries and Tracking Rotated Logs

Most operational debugging tasks focus on either the beginning of a configuration file or the very latest events recorded by an application. Reading the entire file to find those lines wastes I/O bandwidth.

head and tail let you slice specific boundaries with minimal overhead:

# Print the first 25 lines of a configuration file
head -n 25 /etc/redis/redis.conf

# Print the last 40 lines of an audit log
tail -n 40 /var/log/audit/audit.log
Enter fullscreen mode Exit fullscreen mode

A common operational trap occurs when tracking active server logs using tail -f. Standard tail -f hooks into the underlying file descriptor of the target file. When background services like logrotate compress and rotate logs, the active file is renamed or moved, and a brand-new file is created with the original filename.

Because standard tail -f follows the inode rather than the filename, it remains attached to the old, unlinked file descriptor and stops displaying new lines.

To avoid missing critical production events, use -F (capitalized):

tail -F /var/log/nginx/access.log
Enter fullscreen mode Exit fullscreen mode

The -F flag instructs tail to track the file by its filename rather than its file descriptor. If the underlying inode changes or the file is temporarily unavailable during log rotation, tail re-establishes its handle on the new file as soon as the service recreates it.

You can also use tail to slice from a specific line number to the end of a file using the plus notation:

# Display output starting from line 150 through the end of the file
tail -n +150 /var/log/messages
Enter fullscreen mode Exit fullscreen mode

4. tac: Bottom-Up Reverse Reading for Fast Crash Diagnostics

Troubleshooting is chronologically inverted. When an alert fires or a container crashes, you want to inspect the failure event that occurred five seconds ago, not the initialization messages recorded when the system booted three weeks ago.

The standard core utility tac prints lines in reverse order, starting from the final line and working backward to the first.

tac /var/log/dpkg.log | head -n 30
Enter fullscreen mode Exit fullscreen mode

This command surfaces the thirty most recent package installations or upgrades without piping through sort -r or forcing the shell to buffer thousands of lines.

When paired with sed, tac provides an efficient way to pull the most recent stack trace from an application log:

tac /var/log/app/error.log | sed '/TRACEBACK_START/q' | tac
Enter fullscreen mode Exit fullscreen mode

The inner tac reverses the log so the latest crash appears first. The sed statement reads until it matches the start marker of the traceback, prints it, and quits immediately. The second tac restores normal chronological order. You get the exact crash context without reading hundreds of megabytes of older events.


5. zless, zcat, and zstdcat: In-Place Compressed Log Inspection

On production machines, log rotation policies quickly compress historical logs using gzip (.gz), xz (.xz), or zstandard (.zst) to save disk space.

Extracting these files to disk with gunzip or unxz simply to check an error message consumes disk storage, adds write cycles to your drive, and creates leftover files that require cleanup.

Linux provides compression-aware utilities that decompress data directly into memory streams:

# Read a gzipped log file using full less keybindings
zless /var/log/nginx/access.log.2.gz

# Stream an xz-compressed archive directly into grep
xzcat /var/log/syslog.3.xz | grep -i "oom-killer"

# Inspect modern zstandard compressed logs
zstdcat /var/log/journal.zst | head -n 25
Enter fullscreen mode Exit fullscreen mode

zless works with all standard less navigation commands, including forward search (/), backward search (?), and horizontal scrolling (-S). You inspect multi-gigabyte compressed files without writing a single uncompressed byte to disk.


6. view: Read-Only Structural Navigation Without Edit Accidents

Opening production configuration files inside an active text editor like vim or nano is dangerous. An accidental key press, stray paste buffer, or an unthinking write command (:wq) can modify critical runtime configurations without leaving a clear trace in your command history.

Using view (which opens Vim in read-only mode, equivalent to vim -R) gives you complete structural navigation tools while protecting the file from accidental writes:

view /etc/kubernetes/manifests/kube-apiserver.yaml
Enter fullscreen mode Exit fullscreen mode

Inside view, the buffer modification flag is disabled. You get the full power of Vim syntax parsing and movement commands:

  • Press % while your cursor is over an opening parenthesis, bracket, or curly brace to jump directly to its matching closing counterpart.
  • Press * to find the next occurrence of the word currently under your cursor.
  • Use zo and zc to open and close code folds, collapsing long YAML blocks or nested structures.
  • Type :set number to turn on contextual line numbering.

If you accidentally strike an edit key, the editor displays an explicit warning and prevents saving changes to disk.


7. nl: Structured Line Numbering with Logical Page Boundaries

When people want line numbers, they often run cat -n. While cat -n works, it numbers every single line indiscriminately, including empty whitespace, trailing breaks, and formatting separators.

The dedicated nl (number lines) utility gives you fine-grained control over how lines are counted, formatted, and displayed:

nl /etc/pam.d/common-auth
Enter fullscreen mode Exit fullscreen mode

By default, nl only assigns numbers to non-empty lines, keeping the output clean and visually tied to functional configuration directives.

You can modify its numbering logic to suit specific file structures:

# Number all lines including blank ones, right-aligned with 4 digits and zero padding
nl -b a -n rz -w 4 /etc/hosts

# Number only lines matching a specific regex pattern
nl -b p'^[[:space:]]*server' /etc/nginx/nginx.conf
Enter fullscreen mode Exit fullscreen mode

nl also understands logical page delimiters (\:\:\:, \:\:, and \: for headers, body, and footers), allowing you to restart line numbering automatically across distinct sections of generated source files or technical reports.


8. column -t: Formatting Jagged Delimited Files into Clean Tables

Reading delimited text files such as /etc/passwd, /etc/fstab, or CSV exports with cat produces jagged, misaligned output because fields have different lengths.

The column utility parses delimited input and aligns it into neat, human-readable vertical tables:

# Format /etc/passwd using the colon delimiter
column -t -s ":" /etc/passwd | head -n 15
Enter fullscreen mode Exit fullscreen mode

The -t flag instructs column to determine the number of columns dynamically, and -s sets the delimiter character.

For whitespace-delimited files like storage mount configurations:

grep -v '^#' /etc/fstab | column -t
Enter fullscreen mode Exit fullscreen mode

Instead of struggling to see where mount points end and filesystem options begin, every field aligns neatly under its respective column.


9. od, hexdump, and xxd: Exposing Invisible Bytes and Encoding Traps

A frustrating shell issue happens when a bash script exits with cryptic syntax errors, yet opening the script with cat shows clean, correct code.

cat does not reveal invisible characters, including:

  • Windows carriage returns (\r\n or CRLF) inserted by editors on non-Linux systems.
  • Zero-width non-breaking spaces copied from online documentation.
  • UTF-8 Byte Order Marks (BOM) added at the beginning of text files.
  • Embedded null bytes or escape codes from corrupted data transfers.

When text files behave unexpectedly, inspect their underlying bytes directly:

# Inspect the first 128 bytes with hex and ASCII side by side using xxd
xxd -l 128 /etc/environment

# Use hexdump in canonical format to check character offsets
hexdump -C /usr/local/bin/deploy.sh | head -n 10

# Inspect character representations with od
od -c /usr/local/bin/entrypoint.sh | head -n 15
Enter fullscreen mode Exit fullscreen mode

Running od -c exposes line endings immediately. A proper Linux newline appears as \n. A file containing Windows line endings displays explicit \r \n character pairs. Catching this with od in five seconds saves hours of debugging broken shell loops.


Quick Reference: Choosing the Right Tool

Syntax highlighting & code files:
Use bat. It provides language-aware colorization, git status in the left gutter, and automatic pager fallback when output overflows your screen.

Multi-gigabyte logs & large dumps:
Use less -FXRS. It memory-maps files with zero RAM overhead, provides forward and backward regex search, and avoids terminal lockups.

Live log monitoring:
Use tail -F. It tracks files across rotation and inode updates rather than losing track of the file descriptor.

Recent errors & stack traces:
Use tac. It traverses files bottom-up so recent events appear first without needing sorting pipelines.

Compressed archives (.gz, .xz, .zst):
Use zless, xzcat, or zstdcat. They stream and inspect compressed files directly in RAM without extracting data to disk.

Safe configuration inspection:
Use view. It provides full Vim movement and syntax folding while preventing accidental modifications.

Readable line numbers:
Use nl. It numbers non-blank lines by default and supports custom regex patterns and padding styles.

Jagged delimited files (CSV, /etc/passwd):
Use column -t -s ":". It aligns delimiter-separated text into structured vertical columns.

Invisible characters & encoding errors:
Use od -c or hexdump -C. It reveals carriage returns, zero-width spaces, and binary corruption instantly.


An Interesting Fact About cat

The cat command was written in 1971 by Ken Thompson and Dennis Ritchie for the First Edition of Unix. Its sole intended purpose was concatenating files: reading contents from multiple sources and combining them into a single stream.

By 1995, engineers overusing cat as a file viewer had become so widespread that the Usenet community created the Useless Use of cat Award (UUOC). The award called out shell pipelines that ran cat file | command instead of using direct shell redirection (command < file) or passing the file as an argument (command file), which eliminates an unnecessary subshell, process fork, and context switch.


Practical Takeaways for Your Daily Workflow

Habits are hard to change, but defaulting to cat for file inspection creates unnecessary friction and risks shell lockups on busy production nodes.

A simple step is adding an alias to your interactive shell profile:

alias cat="bat 2>/dev/null || less"
Enter fullscreen mode Exit fullscreen mode

Save cat for its original purpose: gluing multiple files together into a pipe (cat chunk.* > full_archive.tar). For reviewing configurations, debugging errors, and inspecting logs, pick the tool designed for that specific data format.


What command or alias do you reach for when a multi-gigabyte log file is filling up disk space on a production server?

If this breakdown saved you hours of debugging or gave you something practical to use in production, consider buying me a coffee. Your support directly fuels independent, zero-fluff Linux and DevOps technical guides.


About the Author

Asep Sayyad is a Linux and DevOps engineer passionate about Linux administration, automation, cloud technologies, containers, and open-source software. He enjoys solving real-world infrastructure challenges and sharing practical knowledge through in-depth technical articles, tutorials, and hands-on guides.

His goal is to help aspiring and experienced engineers build stronger Linux and DevOps skills with content focused on real production scenarios rather than theory alone.

Connect with Me

Enjoyed this article?

If this guide saved you hours of debugging or gave you something practical for production, consider:

  • Buying me a coffee: Your support directly fuels independent, zero-fluff Linux and DevOps engineering breakdowns.
  • Starring my open-source projects on GitHub.
  • Sharing this article with fellow Linux and DevOps engineers.

You can also follow me for more practical content on Linux, DevOps, Cloud, Containers, Automation, and Open Source. Thanks for reading, and enjoy your learning!

© 2026 Asep Sayyad

Top comments (0)