Linux: テキスト処理三銃士 — awk / sed / cut

grepが「探す」ためのものなら、awk、sed、cutは「変える」ためのものです。cutは列を切り出し、awkはデータレポートを生成し、sedは一括置換を行います — パイプと組み合わせれば、ほぼあらゆるテキストタスクを処理できます。

📋 前提条件:まず以下を完了していること

1. このレッスンで学ぶこと


2. CSVファイル処理ストーリー

(1) 悩み:CSVファイルのフォーマット変換が必要

小明はCSVファイルを受け取り、2列目と5列目を抽出し、空行を削除し、区切り文字をカンマからタブに変更する必要がありました。

(2) 1パイプラインチェーンで完結

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

(3) 得られるもの:プログラミング不要のデータ処理

小明はExcelを開いたりPythonスクリプトを書いたりする手間を省きました。1コマンドでデータ処理完了。


3. 知識ポイント

(1) cut — 列で切り出し

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

> ℹ️ 注意:`cut`は単純な列抽出(固定区切り文字、固定列番号)に適しています。条件フィルタリング、計算、フォーマットが必要な場合は`awk`を使用してください。例えば`awk -F: '$3 >= 1000 {print $1}' /etc/passwd`はUID ≥ 1000のユーザーをフィルタリングできます — `cut`では不可能です。

# 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 — データレポートジェネレーター

awkは完全なテキスト処理言語です。コアパターンは:

BASH
awk 'pattern {action}' file

awk組み込み変数:

変数 意味
$0 行全体
$1 第1フィールド
$2 第2フィールド
NF フィールド数
NR 行番号
FS 入力フィールド区切り文字(デフォルト:スペース/タブ)
OFS 出力フィールド区切り文字(デフォルト:スペース)
💡 ヒント:awkのコア変数を暗記しましょう — $0は行全体、$1/$2/$3はフィールド1/2/3、NRは行番号、NFはフィールド数($NFは最後のフィールド)。-F:で区切り文字を指定すれば、大部分のテキスト抽出タスクに対応できます。

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 — ストリームエディタ

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

> 💡 ヒント:`sed -i`は元ファイルをその場で変更し、元に戻せません。まず`-i`なしでプレビュー:`sed 's/old/new/g' file.txt`、確認後に`-i`を追加。または`sed -i.bak`で自動バックアップを作成。

# 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 — 文字変換

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 — ファイル比較

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) ▶ サンプル:cutによる列切り出し

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

出力:

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) ▶ サンプル:awkによる列処理

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}'

出力:

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) ▶ サンプル:sed一括置換

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

出力:

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) ▶ サンプル:tr文字変換

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'

出力:

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) ▶ サンプル:diffファイル比較

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) ▶ 総合例:システム監視レポート

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 "========================================="

❓ よくある質問

Q: awkはcutより何が強力ですか? A: cutは単純な列切り出し(固定区切り文字)しかできません。awkは条件フィルタリング、計算、フォーマット出力をサポートします。awkは完全なプログラミング言語 — 変数、配列、ループ、関数をサポート。単純な場面ではcut、複雑な場面ではawkを使いましょう。

Q: sed -iで元ファイルを変更するのは危険ですか? A: はい — sed -iは元ファイルをその場で変更し、元に戻せません。まず-iなしでプレビューするか、sed -i.bakで自動バックアップを作成。結果を確認したら.bakファイルを削除できます。

Q: diffとvimdiffの違いは? A: diffはコマンドラインツールでテキスト比較結果を出力。vimdiffはvimの視覚比較モードで、左右分割画面とインタラクティブ編集が可能。簡単な比較にはdiff、複雑な比較にはvimdiffを。

Q: trは中国語文字を処理できますか? A: できますが、注意が必要。中国語文字はUTF-8マルチバイトエンコーディングで、trはバイト単位で処理するため、文字を分割する可能性があります。中国語テキストにはsedやPythonを使用してください。

Q: 複数のテキスト処理コマンドを最も効率よく組み合わせるには? A: 原則は「1パス、複数操作」。単純なフィルタリング(grep)を先に置いてデータ量を減らし、重い処理を後にします。cat file | grep | awk | sed | ...のように中間パイプを増やしすぎないように。


📖 まとめ


📝 練習問題

  1. 基本(難易度 ⭐):cutで/etc/passwdからユーザー名、UID(3列目)、ログインシェルを抽出し、trで/etc/hostnameの内容を大文字に変換する
  2. 中級(難易度 ⭐⭐):awkでls -l出力から1MB以上のファイルをフィルタリングし、sedで設定ファイルのポート番号(8080 → 9090)を一括置換し、元ファイルのバックアップを作成する
  3. 上級(難易度 ⭐⭐⭐):わずかに異なる2つの設定ファイルを作成し、diff -uで差分を確認し、パイプラインチェーンでログファイルからエラー行を抽出し、時間別にエラーをカウントし、ピーク時間トップ5を出力する
Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%