Linux & IT ノート

テキスト処理:grep・sed・awk 入門

管理人 約9分で読めます

Unix の設計思想のひとつに「テキストを流して処理する」というものがあります。コマンドはそれぞれ単機能に徹し、標準入出力でつないで組み合わせる――パイプ(|)を使ったワンライナーがその体現です。

今回扱う grepsedawk は、そのパイプラインの中心を担うテキスト処理の三本柱です。役割分担はシンプルで、grep は「検索・絞り込み」、sed は「変換・置換」、awk は「列の抽出と集計」です。サーバーログの解析や設定ファイルの一括書き換えなど、日常的な Linux 操作でこの3つを使いこなせれば、大半のテキスト処理は手の届く範囲に収まります。

grep:テキストを検索・絞り込む

grep はファイルや標準入力から、パターンに一致する行を抽出します。正規表現が使えるのが強みで、単純な文字列検索から複雑なパターンマッチまで対応します。

# 基本:ファイルから "error" を含む行を表示
grep "error" /var/log/syslog

# -i:大文字・小文字を無視
grep -i "error" /var/log/syslog

# -n:行番号を表示
grep -n "error" /var/log/syslog

# -v:パターンに一致しない行を表示(除外)
grep -v "DEBUG" app.log

# -r:ディレクトリを再帰的に検索
grep -r "TODO" ./src/

# -r と -n を組み合わせる(よく使う)
grep -rn "TODO" ./src/

拡張正規表現(-E)

-E オプションを付けると拡張正規表現が使えます。|(OR)や +(1回以上)、?(0または1回)などが利用できます。

# "error" または "warning" を含む行
grep -E "error|warning" app.log

# IPアドレスっぽい文字列を探す
grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" access.log

パイプとの組み合わせ

grep の真価はパイプで発揮されます。他のコマンドの出力を絞り込む用途が非常に多いです。

# 実行中の nginx プロセスを確認
ps aux | grep nginx

# 確認中に grep 自身が出てきてしまう場合は [n]ginx で回避できる
ps aux | grep "[n]ginx"

# ポート 80 を使っているプロセスを探す
ss -tlnp | grep :80

# journalctl のログをリアルタイムに grep
journalctl -fu nginx | grep "502"

sed:テキストを変換・置換する

sed(Stream EDitor)は、ストリームとして流れるテキストを行単位で編集するコマンドです。最も使うのは s コマンド(substitute)による置換です。

# 基本の置換:最初のマッチのみ
sed 's/old/new/' file.txt

# g フラグで行内の全マッチを置換
sed 's/old/new/g' file.txt

# 大文字小文字を無視して置換(GNU sed)
sed 's/old/new/gi' file.txt

# 特定の行のみ置換(5行目だけ)
sed '5s/old/new/' file.txt

-i でファイルを直接書き換える

-i オプションを付けると、ファイルを直接書き換えます(インプレース編集)。バックアップを作りたい場合は -i.bak のように拡張子を指定します。

# ファイルを直接書き換え(バックアップなし)
sed -i 's/http:/https:/g' config.txt

# バックアップを作りながら書き換え
sed -i.bak 's/http:/https:/g' config.txt
# → config.txt.bak に元のファイルが残る

-i はやり直しが効かないため、重要なファイルには必ず -i.bak を使う習慣をつけましょう。

行の削除

# "DEBUG" を含む行を削除
sed '/DEBUG/d' app.log

# 空行を削除
sed '/^$/d' file.txt

# 先頭の5行を削除
sed '1,5d' file.txt

awk:列の抽出と集計

awk はフィールド(列)ベースのテキスト処理が得意なプログラミング言語兼コマンドです。CSV やログのような「区切り文字で分割されたデータ」を扱うのに向いています。

デフォルトの区切り文字は空白(スペース・タブ)で、各フィールドは $1$2… と参照します。$0 は行全体を指します。

# /etc/passwd の最初のフィールド(ユーザー名)を表示
awk -F: '{print $1}' /etc/passwd

# -F でフィールド区切りを指定(ここは : )
# カンマ区切り CSV なら -F,

# ディスク使用量の一覧から使用率($5)とマウント先($6)だけ表示
df -h | awk '{print $5, $6}'

NR・NF

NR(Number of Records)は現在の行番号、NF(Number of Fields)は現在の行のフィールド数です。

# 行番号付きで表示
awk '{print NR, $0}' file.txt

# 最後のフィールドだけ表示(フィールド数が行によって異なる場合に便利)
awk '{print $NF}' file.txt

# ヘッダー行(1行目)をスキップ
awk 'NR > 1 {print $0}' data.csv

条件付き出力と集計

# 第3フィールドが 1000 より大きい行だけ表示
awk '$3 > 1000 {print $0}' data.txt

# 第2フィールドの合計を計算
awk '{sum += $2} END {print "合計:", sum}' data.txt

# 行数のカウント(wc -l と同じ)
awk 'END {print NR}' file.txt

パイプラインでの組み合わせ実例

3つのコマンドを組み合わせると、複雑なログ解析もワンライナーで書けます。

以下は Nginx のアクセスログから、HTTP 500 エラーになったリクエスト先 URL の出現回数を集計する例です。

grep " 500 " /var/log/nginx/access.log \
  | awk '{print $7}' \
  | sort \
  | uniq -c \
  | sort -rn \
  | head -10

処理の流れを追うと:

  1. grep " 500 " … ステータスコード 500 の行だけ絞り込む
  2. awk '{print $7}' … Nginx のデフォルトログ形式で7番目フィールドがリクエスト URI
  3. sort … 同一 URI をまとめるために並び替え
  4. uniq -c … 連続する同じ行をカウントして集約
  5. sort -rn … 件数の多い順に並び替え
  6. head -10 … 上位10件だけ表示

grep で絞り、awk で列を選び、sort | uniq -c | sort -rn で集計するこのパターンは、ログ解析の定番形式として覚えておく価値があります。

実践的なコツと落とし穴

sed -i の破壊性

前述の通り、-i はファイルを即座に上書きします。複数ファイルへの再帰的な適用(find . -name "*.conf" -exec sed -i ... {} \;)は特に注意が必要です。まず -i なしで出力を確認し、問題なければ -i.bak で書き換えるのが安全な手順です。

ロケールと正規表現方言

grep の正規表現の挙動は、環境変数 LC_ALLLANG の設定(ロケール)に影響される場合があります。スクリプトで安定した動作を求めるなら LC_ALL=C grep ... のように先頭で固定するのが無難です。また、macOS と Linux(GNU)では sed-i の挙動が微妙に異なります(macOS では -i '' と書く必要がある)。他者の環境でも動かしたいスクリプトでは注意しましょう。

ripgrep という選択肢

大規模なリポジトリや深いディレクトリツリーを検索するなら、rg(ripgrep)も検討に値します。デフォルトで .gitignore を尊重し、並列処理で grep -r より高速なことが多いです。ただし標準ツールではないので、インフラやサーバー上での利用は grep が無難です。手元の開発環境では rg、本番スクリプトでは grep と使い分けるのが現実的です。

まとめ

  • grep … パターンで行を絞り込む。-i-r-n-v-E を押さえれば大半のユースケースに対応できる
  • seds/old/new/g の置換が中心。-i.bak でインプレース編集
  • awk … フィールド処理と集計。-F で区切り指定、NR/NFEND ブロックを使いこなす

3つを組み合わせたパイプラインは、ログ解析・設定ファイル管理・データ抽出など幅広い場面で役立ちます。最初は「これは grep の仕事か、awk の仕事か」を考えながら使い分けることで、自然と使いどころが身についていきます。

次回(#7)はネットワーク周りに踏み込みます。ip コマンドや sscurl など、サーバー運用で欠かせないツール群を扱う予定です。