Linux - Viewing File Contents

6 minute read

Linux provides a rich set of commands for reading, monitoring, and processing file contents — from simple display to real-time log following and data analysis.


cat — Display Entire File

cat (concatenate) prints the full contents of a file to the terminal:

# Display a file
cat /etc/hostname
# server-01

cat ~/.bashrc
# (prints entire .bashrc)

# Number lines (-n)
cat -n /etc/hosts
#      1  127.0.0.1   localhost
#      2  127.0.1.1   server-01
#      3
#      4  # IPv6 addresses

# Show non-printing characters (-A useful for debugging whitespace issues)
cat -A config.txt
# name=ubuntu$
# path=/home/ubuntu$
# secret=abc ^Idef$    ← ^I is a tab character

# Concatenate multiple files into one
cat file1.txt file2.txt file3.txt > combined.txt

# Append to a file
cat >> notes.txt << 'EOF'
This line is appended.
And this one too.
EOF

When NOT to use cat: for large files, use less instead. Cat dumps the entire file — a 500 MB log file will flood your terminal.


less — Scroll Through Files

less is the standard way to view large files — it lets you scroll up and down without loading the entire file into memory:

# Open a file in less
less /var/log/syslog

# Navigation in less:
# Space or f    → Forward one page
# b             → Back one page
# j or ↓        → Down one line
# k or ↑        → Up one line
# G             → Jump to end of file
# g             → Jump to start of file
# /pattern      → Search forward for pattern
# ?pattern      → Search backward for pattern
# n             → Next search match
# N             → Previous search match
# q             → Quit

# Open with line numbers
less -N /var/log/syslog

# Follow new content as it's appended (like tail -f)
less +F /var/log/syslog
# Press Ctrl+C to stop following, then use normal navigation
# Press F again to resume following

head — View the Beginning of a File

# Default: first 10 lines
head /var/log/syslog
# Apr  1 00:00:01 server-01 systemd[1]: Starting...
# Apr  1 00:00:01 server-01 kernel: [    0.000000] ...
# ... (10 lines)

# Specify number of lines (-n)
head -n 20 /var/log/syslog     # First 20 lines
head -20 /var/log/syslog       # Shorthand

# First 100 bytes (-c)
head -c 100 binary-file

# Show first lines of multiple files
head -n 5 file1.txt file2.txt
# ==> file1.txt <==
# Line 1
# Line 2
# ...
# ==> file2.txt <==
# Line 1
# ...

# Show all lines EXCEPT the last N (GNU head)
head -n -5 file.txt   # All lines except last 5

tail — View the End of a File

# Default: last 10 lines
tail /var/log/auth.log

# Specify number of lines
tail -n 50 /var/log/syslog     # Last 50 lines
tail -50 /var/log/syslog       # Shorthand

# Follow a file in real-time (most useful for live logs)
tail -f /var/log/nginx/access.log
# 2025-04-01 10:00:01 GET / 200 1234
# 2025-04-01 10:00:02 GET /api/users 200 892
# ... (new lines appear as they are written)
# Press Ctrl+C to stop

# Follow with retry (-F): keeps following even if the file is rotated/deleted
tail -F /var/log/nginx/access.log
# More robust than -f for long-running monitoring

# Combine: start at line N and follow
tail -n 100 -f /var/log/syslog   # Last 100 lines, then follow

# Show last N bytes
tail -c 1024 /var/log/syslog    # Last 1024 bytes

# Print from line N to end of file
tail -n +20 file.txt   # From line 20 to end

Real-world log monitoring pattern:

# Monitor multiple log files at once
tail -f /var/log/nginx/access.log /var/log/nginx/error.log

# Filter live log output
tail -f /var/log/syslog | grep --line-buffered "ERROR"

# Timestamp filtered log lines
tail -f /var/log/app.log | while read line; do
    echo "$(date +%T) $line"
done

wc — Word, Line, and Byte Count

# Count lines (-l), words (-w), bytes/characters (-c)
wc /etc/passwd
#  45  90 2345 /etc/passwd
#  ↑   ↑  ↑
# lines words bytes

# Count only lines
wc -l /etc/passwd
# 45 /etc/passwd

# Count lines in multiple files
wc -l /var/log/*.log
#   500 access.log
#    42 error.log
#   542 total

# Count words
wc -w document.txt
# 1234 document.txt

# Count characters
wc -c file.txt    # bytes
wc -m file.txt    # characters (handles multibyte UTF-8)

# Practical: how many processes are running?
ps aux | wc -l
# 143

# How many files in a directory?
ls /etc | wc -l
# 184

# How many lines of code in a project?
find . -name "*.go" | xargs wc -l | tail -1
# 15234 total

sort — Sort Lines

# Sort alphabetically (default)
sort names.txt
# Alice
# Bob
# Charlie

# Reverse sort (-r)
sort -r names.txt
# Charlie
# Bob
# Alice

# Numeric sort (-n) — avoids lexicographic issues with numbers
sort -n numbers.txt
# 1
# 9
# 42
# 100
# (without -n: 1, 100, 42, 9  ← wrong)

# Sort by a specific field (-k)
# File format: name score (space-separated)
sort -k2 -n scores.txt
# alice 85
# bob 92
# charlie 100

# Reverse numeric sort (largest first)
sort -k2 -rn scores.txt
# charlie 100
# bob 92
# alice 85

# Sort and remove duplicates (-u)
sort -u duplicates.txt

# Sort file sizes (human-readable) — list top 10 biggest files
du -sh /var/log/* | sort -rh | head -10
# 45M  /var/log/syslog
# 12M  /var/log/auth.log

uniq — Remove or Report Duplicates

uniq only removes adjacent duplicates — always sort first:

# Sample file with duplicates
cat access.log | grep "404" | awk '{print $7}' | sort | uniq
# /api/missing
# /old-page
# /favicon.ico

# Count occurrences (-c)
sort words.txt | uniq -c
#      5 apple
#      2 banana
#      8 cherry

# Sort by count (most frequent first)
sort words.txt | uniq -c | sort -rn
#      8 cherry
#      5 apple
#      2 banana

# Show only duplicate lines (-d)
sort file.txt | uniq -d

# Show only unique lines (-u)
sort file.txt | uniq -u

cut — Extract Fields from Lines

# Cut by character position (-c)
cut -c1-5 file.txt      # First 5 characters of each line
cut -c1,3,5 file.txt    # Characters 1, 3, and 5

# Cut by delimiter (-d) and field (-f)
# /etc/passwd uses : as delimiter
cut -d: -f1 /etc/passwd        # Username only
# root
# daemon
# ubuntu

cut -d: -f1,6 /etc/passwd      # Username and home directory
# root:/root
# daemon:/usr/sbin
# ubuntu:/home/ubuntu

cut -d: -f3- /etc/passwd       # Fields 3 to end

# CSV processing
echo "name,age,city" | cut -d, -f2
# age

# Extract the date from log lines
# Log format: "2025-04-01 10:00:01 [INFO] Server started"
cat app.log | cut -d' ' -f1
# 2025-04-01
# 2025-04-01
# 2025-04-01

Combining Commands with Pipes

These commands are most powerful when combined:

# Top 10 most frequent IP addresses in nginx access log
awk '{print $1}' /var/log/nginx/access.log | \
    sort | \
    uniq -c | \
    sort -rn | \
    head -10
# 1234 192.168.1.1
#  892 10.0.0.45
#  567 172.16.0.12

# Count unique HTTP status codes
awk '{print $9}' /var/log/nginx/access.log | \
    sort | \
    uniq -c | \
    sort -rn
# 98234 200
#  1234 304
#   892 404
#    45 500

# Find the largest files, human-readable
find /var/log -type f | xargs ls -lh | sort -k5 -rh | head -10

# Word frequency analysis
cat document.txt | \
    tr '[:upper:]' '[:lower:]' | \
    tr -cs '[:alpha:]' '\n' | \
    sort | \
    uniq -c | \
    sort -rn | \
    head -20

Key Takeaways

  • cat — print small files; avoid on large files
  • less — the right tool for large files; /pattern to search inside
  • head -n N — first N lines; tail -n N — last N lines
  • tail -f — follow a log file in real-time; tail -F is more robust for rotated logs
  • wc -l — count lines; pipe anything through wc -l to count results
  • sort -n — numeric sort; sort -rn — reverse numeric; sort -k2 — sort by field 2
  • uniq -c — count occurrences; always sort before uniq
  • cut -d: -f1 — extract first colon-delimited field; essential for parsing structured text

← Back to File Management Commands Next → Getting Help

Updated: