Linux: The Three Musketeers of Text Processing

If grep is for "finding," then awk, sed, and cut are for "changing." cut slices columns, awk generates data reports, sed does bulk replacements — together with pipes, they can handle nearly any text task.

📋 Prerequisites: You should already know

1. What You'll Learn


2. A CSV File Processing Story

(1) The Pain Point: CSV File Needs Format Conversion

Xiaoming received a CSV file and needed to extract columns 2 and 5, remove blank lines, and change the delimiter from commas to tabs.

(2) One Pipeline Chain Does It All

BASH
cat data.csv | cut -d',' -f2,5 | sed '/^$/d' | tr ',' '\t' > output.tsv

(3) The Benefit: Data Processing Without Programming

Xiaoming skipped the hassle of opening Excel or writing a Python script. One command, data processing done.


3. Knowledge Points

(1) cut — Slice by Column

BASH
# Split by delimiter
cut -d',' -f1,3 file.csv    # Delimiter comma, take columns 1 and 3
cut -d: -f1 /etc/passwd     # Delimiter colon, take usernames

> ℹ️ Note: `cut` is suitable for simple column extraction (fixed delimiter, fixed column numbers). For scenarios requiring conditional filtering, calculation, or formatting, use `awk` instead. For example, `awk -F: '$3 >= 1000 {print $1}' /etc/passwd` can filter users with UID ≥ 1000 — `cut` cannot do that.

# Split by character position
cut -c1-5 file.txt          # Take characters 1-5
cut -c1,3,5 file.txt        # Take characters 1, 3, and 5

(2) awk — Data Report Generator

awk is a complete text processing language. Its core pattern is:

BASH
awk 'pattern {action}' file

awk Built-in Variables:

Variable Meaning
$0 Entire line
$1 First field
$2 Second field
NF Number of fields
NR Line number
FS Input field separator (default: space/tab)
OFS Output field separator (default: space)
💡 Tip: Memorize awk's core variables — $0 is the whole line, $1/$2/$3 are fields 1/2/3, NR is the line number, NF is the field count ($NF is the last field). With -F: to specify a delimiter, you can handle most text extraction tasks.

BASH
# Basic usage
awk '{print $1}' file.txt           # Print column 1
awk '{print $1, $3}' file.txt       # Print columns 1 and 3
awk '{print NR, $0}' file.txt       # Print line number and entire line
awk '{print $NF}' file.txt           # Print last column
awk -F: '{print $1}' /etc/passwd    # Specify colon as delimiter

# Pattern matching
awk '/error/ {print}' log.txt       # Only process lines containing error
awk '$3 > 100 {print $1, $3}' data.txt  # Output only when column 3 > 100

# Aggregation
awk '{sum += $1} END {print sum}' numbers.txt  # Sum
awk '{count++} END {print count}' file.txt     # Count

(3) sed — Stream Editor

BASH
# Replace
sed 's/old/new/' file.txt          # Replace first occurrence per line
sed 's/old/new/g' file.txt         # Global replace
sed 's/old/new/2' file.txt         # Replace only 2nd occurrence per line
sed 's/old/new/g' file.txt > new.txt  # Output to new file
sed -i 's/old/new/g' file.txt     # In-place edit (modifies file directly)
sed -i.bak 's/old/new/g' file.txt # Backup original as file.txt.bak

> 💡 Tip: `sed -i` modifies the file in place with no undo. Preview the result first without `-i`: `sed 's/old/new/g' file.txt`, then add `-i` once confirmed. Or use `sed -i.bak` to automatically create a backup.

# Delete
sed '/pattern/d' file.txt          # Delete lines matching pattern
sed '3d' file.txt                  # Delete line 3
sed '5,10d' file.txt               # Delete lines 5-10
sed '/^$/d' file.txt               # Delete blank lines

# Print
sed -n '5,10p' file.txt            # Print only lines 5-10
sed -n '/pattern/p' file.txt       # Print only matching lines

(4) tr — Character Translation

BASH
# Case conversion
echo "hello" | tr 'a-z' 'A-Z'      # HELLO
cat file.txt | tr '[:lower:]' '[:upper:]'

# Replace and delete
echo "a,b,c" | tr ',' ' '          # a b c
echo "hello   world" | tr -s ' '   # hello world (squeeze repeated spaces)
echo "hello123" | tr -d '0-9'      # hello (delete digits)
echo "abc123" | tr -d '[:digit:]'  # abc (delete digits)

# Line ending conversion (Windows ↔ Unix)
tr -d '\r' < win.txt > unix.txt    # Remove Windows CR
tr '\n' ',' < list.txt             # Replace newlines with commas

(5) diff — File Comparison

TEXT
diff file1.txt file2.txt           # Basic comparison
diff -u file1.txt file2.txt        # Unified format (more readable)
diff -i file1.txt file2.txt        # Ignore case
diff -w file1.txt file2.txt        # Ignore whitespace differences
diff -r dir1/ dir2/                # Recursive directory comparison

(6) ▶ Example: cut Column Slicing

BASH
# Extract username and shell from /etc/passwd
cut -d: -f1,7 /etc/passwd | head -5
# root:/bin/bash
# daemon:/usr/sbin/nologin
# bin:/usr/sbin/nologin

# Take column 5 (file size) from ls -l output
ls -la | tr -s ' ' | cut -d' ' -f5 | head -5

Output:

TEXT
root:/bin/bash
daemon:/usr/sbin/nologin
bin:/usr/sbin/nologin
sys:/usr/sbin/nologin
sync:/usr/sbin/nologin
4096
4096
1234
5678
910

(7) ▶ Example: awk Column Processing

BASH
# Print username and home directory
awk -F: '{print $1, "Home:", $6}' /etc/passwd | head -5

# Find regular users with UID greater than 1000
awk -F: '$3 >= 1000 {print $1, "(UID:" $3 ")"}' /etc/passwd

# Calculate total file size
ls -la | grep "^-" | awk '{sum += $5} END {print "Total:", sum/1024/1024, "MB"}'

# Formatted output (printf)
ls -la | awk '{printf "%-20s %8s\n", $9, $5}'

Output:

TEXT
root Home: /root
daemon Home: /usr/sbin
bin Home: /bin
sys Home: /dev
nobody Home: /nonexistent
alice (UID:1000)
bob (UID:1001)
Total: 256.5 MB
.bashrc                 3771
.profile                220
.bash_history           1234

(8) ▶ Example: sed Bulk Replace

BASH
# Replace localhost with 127.0.0.1 in the file
sed -i 's/localhost/127.0.0.1/g' config.txt

# Comment out lines starting with listen in the config file
sed -i '/^listen/s/^/#/' nginx.conf

# Insert a new line after line 2
sed '2a\New line inserted' file.txt

# Extract timestamps from log file
sed -n 's/.*\[\(.*\)\].*/\1/p' access.log | head -5

Output:

TEXT
07/Jul/2026:10:15:30 +0000
07/Jul/2026:10:15:31 +0000
07/Jul/2026:10:15:32 +0000
07/Jul/2026:10:15:33 +0000
07/Jul/2026:10:15:34 +0000

(9) ▶ Example: tr Character Translation

BASH
# Count words in text
cat file.txt | tr -s ' ' '\n' | sort | uniq -c | sort -rn | head -10

# Convert a list to a single comma-separated line
cat list.txt | tr '\n' ',' | sed 's/,$//'

# Remove all comments and blank lines from a config file
grep -v "^#" config.txt | grep -v "^$" | tr -s '\n'

Output:

TEXT
    42 the
    28 and
    25 linux
    20 file
    18 command
    15 user
    12 system
    10 process
     8 directory
     6 shell
apple,banana,cherry,date
ServerName localhost
Listen 80
DocumentRoot /var/www/html
ErrorLog /var/log/apache2/error.log

(10) ▶ Example: diff File Comparison

TEXT
# Create two versions
echo -e "apple\nbanana\norange" > v1.txt
echo -e "apple\nblueberry\norange" > v2.txt

# Compare
diff -u v1.txt v2.txt
# --- v1.txt
# +++ v2.txt
# @@ -1,3 +1,3 @@
#  apple
# -banana
# +blueberry
#  orange

(11) ▶ Comprehensive Example: System Monitoring Report

BASH
#!/bin/bash
# sys-report.sh - Generate system monitoring report

echo "========================================="
echo "        System Monitoring Report"
echo "        Generated at: $(date)"
echo "========================================="
echo ""

echo "1. Top 5 Processes by CPU Usage"
ps aux --sort=-%cpu | head -6 | awk '{printf "%-10s %-5s %-5s %s\n", $1, $2, $3, $11}'

echo ""
echo "2. Disk Usage"
df -h | grep "^/" | awk '{printf "%-20s %5s %5s %5s\n", $6, $2, $3, $5}'

echo ""
echo "3. Top 5 by Memory Usage"
ps aux --sort=-%mem | head -6 | awk '{printf "%-10s %-5s %-5s %s\n", $1, $2, $4, $11}'

echo ""
echo "4. Error Count in /var/log"
grep -ric "error" /var/log/*.log 2>/dev/null | grep -v ":0" | head -10

echo ""
echo "5. Listening Ports"
ss -tlnp | tail -n +2 | awk '{print $4, $1}' | sed 's/.*://'

echo ""
echo "========================================="

❓ FAQ

Q: What makes awk more powerful than cut? A: cut can only do simple column slicing (fixed delimiter). awk supports conditional filtering, calculations, and formatted output. awk is a complete programming language — it supports variables, arrays, loops, and functions. Use cut for simple scenarios, awk for complex ones.

Q: Is sed -i risky for modifying the original file? A: Yes — sed -i modifies the file in place with no undo. Preview without -i first, or use sed -i.bak to automatically create a backup. After confirming the result, you can delete the .bak file.

Q: What's the difference between diff and vimdiff? A: diff is a command-line tool that outputs text comparison results. vimdiff is vim's visual comparison mode with side-by-side split screen and interactive editing. Use diff for quick comparisons, vimdiff for complex ones.

Q: Can tr handle Chinese characters? A: It can, but with caution. Chinese characters are UTF-8 multi-byte encoded, and tr processes by byte, which may split Chinese characters. For Chinese text, use sed or Python instead.

Q: How to combine multiple text processing commands most efficiently? A: The principle is "one pass, multiple operations." Put simple filtering (grep) first to reduce data volume, then heavier processing later. Avoid creating too many intermediate pipes in cat file | grep | awk | sed | ....


📖 Summary


📝 Exercises

  1. Basic (⭐): Use cut to extract usernames, UIDs (column 3), and login shells from /etc/passwd, then use tr to convert the content of /etc/hostname to uppercase
  2. Intermediate (⭐⭐): Use awk to filter files larger than 1MB from ls -l output, then use sed to batch replace a port number (8080 → 9090) in a config file, creating a backup of the original
  3. Challenge (⭐⭐⭐): Create two slightly different config files, use diff -u to view differences, then write a pipeline chain to extract all error lines from a log file, count errors by hour, and output the top 5 peak hours
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏