|

Linux 13 🐧 uniq, head, tail and tee commands

These four commands handle specific parts of file processing: finding duplicates, viewing the start or end of files, and simultaneously displaying and saving output.


Overview

CommandPurposeBest For
uniqFilter duplicate linesRemoving/finding duplicates in sorted files
headShow beginning of filePreviewing files
tailShow end of fileViewing recent log entries
teeWrite to file AND displayLogging while watching output

The uniq Command

Filters out duplicate lines from a sorted file.

cat data.txt
uniq data.txt
uniq -c data.txt
uniq -d data.txt
uniq -u data.txt

⚠️ Important: uniq only removes adjacent duplicates. Sort the file first!

OptionDescription
(none)Remove adjacent duplicate lines
-cCount the number of times each line appears
-dShow only duplicate lines
-uShow only unique lines
-iIgnore case
-f NSkip first N fields

Examples

Sample file:

$ cat data.txt
apple
apple
banana
banana
banana
cherry
cherry
date

Basic uniq (removes adjacent duplicates):

$ uniq data.txt
apple
banana
cherry
date

Count occurrences (-c):

$ uniq -c data.txt
      2 apple
      3 banana
      2 cherry
      1 date

Only duplicates (-d):

$ uniq -d data.txt
apple
banana
cherry

Only unique (-u):

$ uniq -u data.txt
date

The uniq + sort Pipeline

This is the classic pattern — sort first, then uniq:

$ cat unsorted.txt
banana
apple
banana
cherry
apple
banana

$ sort unsorted.txt | uniq
apple
banana
cherry

$ sort unsorted.txt | uniq -c
      2 apple
      3 banana
      1 cherry

$ sort unsorted.txt | uniq -c | sort -rn
      3 banana
      2 apple
      1 cherry

Word frequency — a common interview task:

$ cat file.txt | tr ' ' '\n' | sort | uniq -c | sort -rn | head -10

The head Command

Displays the beginning of a file. Default: 10 lines.

head -n 2 data.txt
head -c 3 data.txt
cat data.txt | head -n 2
OptionDescription
(none)Show first 10 lines
-n NShow first N lines
-c NShow first N bytes
-qQuiet (no headers with multiple files)
-vAlways show headers

Examples

First 10 lines (default):

$ head data.txt
# Shows first 10 lines

First N lines:

$ head -n 2 data.txt
Line 1
Line 2

$ head -n 5 log.txt
# First 5 lines

First N bytes:

$ head -c 3 data.txt
Lin

$ head -c 10 data.txt
Line 1
Li

Multiple files:

$ head -n 2 file1.txt file2.txt
==> file1.txt <==
Line 1
Line 2

==> file2.txt <==
Alpha
Beta

With pipe:

$ cat data.txt | head -n 2
Line 1
Line 2

$ ls -l | head -n 5
# First 5 lines of directory listing

Negative numbers (GNU extension):

$ head -n -5 data.txt
# Shows all lines EXCEPT the last 5

The tail Command

Displays the end of a file. Default: 10 lines.

tail -n 2 data.txt
cat data.txt | tail -n 2
OptionDescription
(none)Show last 10 lines
-n NShow last N lines
-c NShow last N bytes
-fFollow — show new lines as they’re added
-FFollow even if file is rotated

Examples

Last 10 lines (default):

$ tail data.txt
# Shows last 10 lines

Last N lines:

$ tail -n 2 data.txt
Line 8
Line 9

$ tail -n 5 log.txt
# Last 5 lines

Last N bytes:

$ tail -c 3 data.txt
ine

The -f flag — follow a log in real-time:

$ tail -f /var/log/syslog
# Displays new lines as they appear
# Ctrl+C to stop

Combine with grep for monitoring:

$ tail -f /var/log/syslog | grep "ERROR"
# Only shows new ERROR lines

Multiple files:

$ tail -n 2 file1.txt file2.txt
==> file1.txt <==
Line 8
Line 9

==> file2.txt <==
Gamma
Delta

Starting from line N:

$ tail -n +3 data.txt
# Starts from line 3 and shows the rest

The tee Command

Reads from stdin, writes to stdout AND a file at the same time.

echo "kronos" | tee data2.txt
echo "kronos2" | tee -a data2.txt
echo "kronos2" | tee data2.txt data3.txt

Visual:

        ┌──────────────────┐
stdin ──│  tee  │──stdout──│  Terminal
        └───────┴──────────┘
                │
                └──file──→ File
OptionDescription
(none)Write to stdout and file (overwrite)
-aAppend to file instead of overwriting
-iIgnore interrupt signals
Multiple filesWrite to all files at once

Examples

Basic tee:

$ echo "kronos" | tee data2.txt
kronos                          # ← displayed on terminal
$ cat data2.txt
kronos                          # ← also saved to file

Append mode (-a):

$ echo "kronos2" | tee -a data2.txt
kronos2
$ cat data2.txt
kronos
kronos2                         # ← both lines saved

Write to multiple files:

$ echo "kronos2" | tee data2.txt data3.txt
kronos2
$ cat data2.txt
kronos2
$ cat data3.txt
kronos2                         # ← saved to both files

Save AND view command output:

$ ls -la | tee file-list.txt
# Displays listing AND saves to file-list.txt

Log while watching:

$ ./script.sh | tee -a script.log
# See live output AND append to log

Privileged write (sudo tee):

$ echo "127.0.0.1 mysite.local" | sudo tee -a /etc/hosts
# Use tee when you need sudo to write
# (sudo redirect ">" doesn't work as expected)

Complete Example Session

# ============================================
# PART 1: UNIQ
# ============================================

# Create a file with duplicates
$ cat > data.txt << EOF
apple
apple
banana
banana
banana
cherry
cherry
date
EOF

# Remove adjacent duplicates
$ uniq data.txt
apple
banana
cherry
date

# Count occurrences
$ uniq -c data.txt
      2 apple
      3 banana
      2 cherry
      1 date

# Only duplicates
$ uniq -d data.txt
apple
banana
cherry

# Only unique
$ uniq -u data.txt
date

# Classic sort | uniq pipeline
$ sort unsorted.txt | uniq -c | sort -rn

# ============================================
# PART 2: HEAD
# ============================================

# First 10 lines (default)
$ head data.txt

# First 2 lines
$ head -n 2 data.txt
apple
apple

# First 3 bytes
$ head -c 3 data.txt
app

# Multiple files
$ head -n 2 file1.txt file2.txt
==> file1.txt <==
...

# With pipe
$ cat data.txt | head -n 2

# ============================================
# PART 3: TAIL
# ============================================

# Last 10 lines (default)
$ tail data.txt

# Last 2 lines
$ tail -n 2 data.txt
cherry
date

# Last 3 bytes
$ tail -c 3 data.txt
ate

# Real-time log monitoring
$ tail -f /var/log/syslog

# Filter followed output
$ tail -f /var/log/syslog | grep "ERROR"

# ============================================
# PART 4: TEE
# ============================================

# Write and display
$ echo "kronos" | tee data2.txt
kronos

# Append
$ echo "kronos2" | tee -a data2.txt
kronos2

# Multiple files
$ echo "kronos2" | tee data2.txt data3.txt
kronos2

# Save command output
$ ls -la | tee file-list.txt

# Using tee with sudo
$ echo "127.0.0.1 myapp.local" | sudo tee -a /etc/hosts

# ============================================
# PART 5: COMBINING THEM
# ============================================

# Top 5 most frequent lines
$ sort file.txt | uniq -c | sort -rn | head -5

# View the beginning and end
$ head -n 5 data.txt && tail -n 5 data.txt

# Watch a log AND save it
$ tail -f /var/log/syslog | tee -a syslog-backup.txt

# Find duplicate IPs in a log
$ grep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" access.log | sort | uniq -c | sort -rn | head -10

# First and last lines of file
$ { head -n 1 file.txt; tail -n 1 file.txt; }

# Save AND display grep results
$ grep "ERROR" log.txt | tee errors.txt | wc -l

# ============================================
# PART 6: PRACTICAL EXAMPLES
# ============================================

# Analyze top visitors
$ awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10

# Watch deployment log with backup
$ tail -f deploy.log | tee -a deploy-backup.txt

# Check first and last entries in a CSV
$ head -n 2 data.csv
$ tail -n 2 data.csv

# Find duplicate filenames
$ ls | sort | uniq -d

# Unique lines only
$ cat file.txt | sort -u

# Recent errors from syslog
$ grep "ERROR" /var/log/syslog | tail -n 20

# Save terminal session
$ script -c "bash" session.log

Quick Reference

uniq Options

OptionDescription
(none)Remove adjacent duplicates
-cCount occurrences
-dDuplicates only
-uUnique only
-iIgnore case

head Options

OptionDescription
(none)First 10 lines
-n NFirst N lines
-c NFirst N bytes
-n -NAll except last N lines

tail Options

OptionDescription
(none)Last 10 lines
-n NLast N lines
-c NLast N bytes
-fFollow (real-time)
-n +NStart from line N

tee Options

OptionDescription
(none)Write (overwrite)
-aAppend
-iIgnore interrupts
file1 file2Multiple files

Best Practices

Do This:

# Always sort before uniq
sort file.txt | uniq

# Use uniq -c for frequency counting
sort file.txt | uniq -c

# Use head to preview before processing
head -n 5 bigfile.txt

# Use tail -f to monitor logs
tail -f /var/log/syslog

# Use tee to see AND save
command | tee output.txt

# Use sudo tee for privileged writes
echo "content" | sudo tee /etc/important.conf

# Combine head and tail to see both ends
head -n 5 file.txt; echo "..."; tail -n 5 file.txt

Don’t Do This:

# Don't use uniq on unsorted files
uniq unsorted.txt          # ❌ Only removes ADJACENT duplicates
sort unsorted.txt | uniq   # ✅ Correct

# Don't forget the -a flag with tee
echo "line 2" | tee file.txt      # ❌ Overwrites!
echo "line 2" | tee -a file.txt   # ✅ Appends

# Don't use > with sudo (misleading)
sudo echo "x" > /etc/file  # ❌ Redirect runs as user, not root
sudo tee /etc/file <<< "x" # ✅ tee runs as root

# Don't tail -f without a way to stop
tail -f log.txt            # Ctrl+C to stop
# (it runs forever, watching the file)

# Don't use uniq for global duplicate removal
sort file.txt | uniq       # ✅ Always sort first

Common Pitfalls

PitfallProblemSolution
uniq on unsorted fileOnly adjacent duplicates removedUse sort | uniq
tee overwritesLoses old dataUse -a to append
sudo > doesn’t workRedirect runs as userUse sudo tee
tail -f on deleted fileKeeps runningUse -F to follow rotations
head/tail without args10 lines defaultAdd -n N for precision
Forgetting to sortuniq misses duplicatesAlways sort first

Real-World Examples

1. Find most common HTTP status codes

awk '{print $9}' access.log | sort | uniq -c | sort -rn

2. Monitor a log for errors in real time

tail -f /var/log/syslog | grep --line-buffered "ERROR"

3. Save and display a command’s output

find /etc -name "*.conf" 2> /dev/null | tee config-files.txt

4. Preview a large file

# First 5 lines and last 5 lines
head -n 5 huge.log; echo "..."; tail -n 5 huge.log

5. Write to a root-owned file

echo "nameserver 8.8.8.8" | sudo tee -a /etc/resolv.conf

6. Top 10 most frequent words in a file

cat book.txt | tr -s ' ' '\n' | sort | uniq -c | sort -rn | head -10

7. Find duplicate lines across multiple files

cat *.txt | sort | uniq -d

8. Count unique visitors from a log

awk '{print $1}' access.log | sort -u | wc -l

9. Watch a log while saving a copy

tail -f app.log | tee -a app-archive.log

10. Verify package installation order

grep "install " /var/log/dpkg.log | tail -n 20

Visual: Command Output

UNIQ:                              HEAD:           TAIL:
Sort removes duplicates            First N lines   Last N lines
                                   ┌──────────┐    ┌──────────┐
Input:     Output:                 │ Line 1   │    │ Line 18  │
apple                              │ Line 2   │    │ Line 19  │
apple    → apple                   │ Line 3   │    │ Line 20  │
banana   → banana                  │ ...      │    │ ...      │
banana   → cherry                  └──────────┘    └──────────┘
cherry   → date                    (head -n 3)     (tail -n 3)
cherry
date

TEE:
              ┌────────────────────┐
stdin  ──→  │    tee -a          │  ──→ stdout (terminal)
              └────────┬───────────┘
                       │
                       └──→ file (saved)

Summary

CommandPurposeExample
uniqFilter duplicatessort file | uniq -c
headShow beginninghead -n 5 file.txt
tailShow endtail -f log.txt
teeSave and displaycmd | tee -a log.txt

Key takeaways:

  • uniq works on sorted input — always sort first for real deduplication
  • uniq -c is your friend for frequency counting
  • head and tail both default to 10 lines and support -n and -c
  • tail -f is the go-to way to monitor logs in real time
  • tee lets you see AND save — perfect for logging
  • tee -a appends instead of overwriting
  • sudo tee is the correct way to write to root-owned files

Remember: These commands are the precision tools of text processing. uniq for duplicates, head/tail for previewing, and tee for logging — combined with sort, grep, and pipes, they let you handle almost any file-processing task. And the most common pattern in the wild? sort | uniq -c | sort -rn | head — the go-to one-liner for “show me the top occurrences of anything”!


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!