sed 入門 - ストリームエディタでテキスト置換
この記事で解決できること
sedの 代表 5 パターン(置換 / 削除 / 印字 / 範囲 / 複数式)を最短ルートで習得できる-iインプレース編集の 事故を避ける型 が身につく- BRE と ERE(
-E)の違いを把握し、grep -E/awkと一貫した正規表現が書けるようになる
結論(実務で使う型)
- まず 標準出力で確認 → 問題なければ
-i.bakで上書き - 区切り文字は
/以外も使える(パスを置換するときは|か#) - 「全置換したい」なら必ず末尾
g。gを忘れると 行内 1 件のみ 置換
前提(対象環境)
- OS: Ubuntu / Debian / RHEL 系 Linux
- 想定 sed: GNU sed(macOS の BSD sed は
-iの書式が異なるため別途注意)
sed とは?
sed(stream editor)は 入力ストリームを 1 行ずつ読み、編集スクリプトを適用して出力する コマンド。対話編集の Vim と違い、シェルパイプライン上で非対話に動く のが本質。ログ整形・設定ファイル一括書き換え・テキスト前処理で使う。
$ echo "hello world" | sed 's/world/Linux/' hello Linux
s/old/new/ は substitute(置換) コマンドで、sed の使用頻度の 8 割を占める。
なぜ最初に「標準出力で確認」が鉄則なのか?
sed -i は ファイルを直接書き換える。書き換えた後で「置換パターンを間違えた」「区切り文字に含まれる / をエスケープし忘れた」と気づくと復旧できない。標準出力に出して 目で確認してから -i を付けるのが事故防止の唯一の型。
# 1. まず標準出力で確認 $ sed 's/foo/bar/g' config.txt # 2. 問題なければバックアップ付きで上書き $ sed -i.bak 's/foo/bar/g' config.txt # 3. config.txt.bak が自動生成されている $ ls config.txt* config.txt config.txt.bak
-i 単独(バックアップなし)は本番運用では非推奨。-i.bak を癖にすると、想定外置換からのロールバックが mv config.txt.bak config.txt で済む。
1. 置換: s/old/new/ の基本形
1-1. 行内最初の 1 件だけ置換(デフォルト)
$ echo "apple apple apple" | sed 's/apple/orange/' orange apple apple
1-2. 行内すべて置換(g フラグ)
$ echo "apple apple apple" | sed 's/apple/orange/g' orange orange orange
g の付け忘れは sed 初心者の最頻出ミス。 「1 行に複数ある置換対象が一部しか変わらない」と感じたらまず g を確認する。
1-3. 大文字小文字を無視(I フラグ)
$ echo "Apple APPLE apple" | sed 's/apple/orange/gI' orange orange orange
I フラグは GNU sed 拡張。POSIX sed には存在しないため、移植性が必要な場面では使わない。
2. 区切り文字を / 以外に変える
置換対象にパス(/usr/local)が含まれると / のエスケープ地獄になる。s 直後の文字が区切り文字になる ため、| # , などを選べる。
# NG: エスケープが必要で読みにくい $ sed 's/\/usr\/local\/bin/\/opt\/bin/' file # OK: パイプを区切り文字に $ sed 's|/usr/local/bin|/opt/bin|' file # OK: # を区切り文字に $ sed 's#/usr/local/bin#/opt/bin#' file
区切り文字を変えるだけでバグの 8 割は消える。パス置換は | か # がデファクト。
3. アドレス指定(範囲を絞る)
sed の編集コマンドは アドレス(範囲)を前置 することで対象行を絞れる。
3-1. 行番号で指定
$ sed '3s/foo/bar/' file # 3 行目のみ $ sed '1,5s/foo/bar/g' file # 1〜5 行目 $ sed '10,$s/foo/bar/g' file # 10 行目〜最終行($ = EOF)
3-2. パターンで指定
# "ERROR" を含む行だけ置換 $ sed '/ERROR/s/foo/bar/g' file # /START/ から /END/ までの範囲で置換 $ sed '/START/,/END/s/foo/bar/g' file
3-3. 否定(!)
# 1 行目「以外」を置換 $ sed '1!s/foo/bar/g' file # コメント行(#始まり)以外で置換 $ sed '/^#/!s/foo/bar/g' file
4. 削除(d)と印字(p)
4-1. 行削除
$ sed '/^$/d' file # 空行を削除 $ sed '/^#/d' file # コメント行(# 始まり)を削除 $ sed '1,5d' file # 1〜5 行目を削除 $ sed '$d' file # 最終行を削除
4-2. 特定行のみ印字(-n + p)
sed のデフォルトは「すべての行を出力 + 編集適用」。-n で デフォルト出力を抑止 し、p コマンドで明示的に出力する。
# "ERROR" を含む行だけ出力(grep "ERROR" と同等) $ sed -n '/ERROR/p' file # 10〜20 行目だけ出力 $ sed -n '10,20p' file
sed -n 'Np' は head -n N | tail -1 より高速で読みやすい。
5. 複数の編集を一度に適用
5-1. -e で複数式
$ sed -e 's/foo/bar/g' -e 's/hoge/fuga/g' file
5-2. セミコロンで連結(GNU sed)
$ sed 's/foo/bar/g; s/hoge/fuga/g' file
5-3. スクリプトファイルから読み込み
繰り返し使う変換セットはファイルに保存できる。
$ cat replace.sed s/foo/bar/g s/hoge/fuga/g /^#/d $ sed -f replace.sed file
6. BRE と ERE:-E を使うべきか?
sed はデフォルトで BRE(基本正規表現) を使う。+ ? | (...) を使うには バックスラッシュでエスケープ が必要で読みにくい。-E を付けると ERE(拡張正規表現) に切り替わり、grep -E / awk と同じ記法になる。
6-1. BRE(デフォルト)
# グループとキャプチャに \( \) が必要
$ echo "2026-05-20" | sed 's/\([0-9]\{4\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}\)/\3\/\2\/\1/'
20/05/20266-2. ERE(-E)
# エスケープ不要で読みやすい
$ echo "2026-05-20" | sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3\/\2\/\1/'
20/05/2026実務では -E を癖にする。 BRE のエスケープは読み手の負担が大きく、レビューでの取りこぼし原因になる。
6-3. 後方参照(\1 \2 ...)
キャプチャした部分は置換側で \1 \2 ... で参照できる。BRE / ERE どちらでも記法は同じ。
# Last, First → First Last に並び替え $ echo "Doe, John" | sed -E 's/(.+), (.+)/\2 \1/' John Doe
7. やってはいけない・事故パターン
事故パターン Top 5
-iを確認なしで実行 → 復旧不能。必ず-i.bakか事前 dry-rung忘れで全置換できない → 行内 1 件しか変わらない- 区切り文字エスケープ漏れ →
|か#に切り替えれば回避 - BRE/ERE 混乱 → 統一して
-Eを使う *.をリテラルとして扱おうとする → 正規表現のメタ文字なのでエスケープ必要
7-1. リテラル文字のエスケープ
# NG: . が「任意の 1 文字」として解釈される $ echo "192x168x0x1" | sed 's/192.168.0.1/X/' X # OK: . をエスケープ $ echo "192x168x0x1" | sed 's/192\.168\.0\.1/X/' 192x168x0x1
7-2. シェル変数を埋め込むとき
シングルクォート内ではシェル変数は展開されない。ダブルクォートに切り替えるが、$ や \ の扱いに注意する。
NEW="bar" # NG: $NEW がそのまま文字列扱い $ sed 's/foo/$NEW/g' file # OK: ダブルクォートで展開 $ sed "s/foo/$NEW/g" file
$NEW の中身に / & \ が含まれると壊れる。安全に変数展開したいなら区切り文字を別の文字に変えるか、printf '%s' "$NEW" でサニタイズする。
8. 実務で使えるレシピ集
コピペ用テンプレート
# CRLF を LF に変換
sed -i.bak 's/\r$//' file
# 空行と # で始まるコメント行を除去
sed -e '/^$/d' -e '/^#/d' /etc/nginx/nginx.conf
# IP アドレスをマスク
sed -E 's/\b([0-9]{1,3}\.){3}[0-9]{1,3}\b/x.x.x.x/g' access.log
# 末尾の空白を削除
sed -i.bak 's/[[:space:]]*$//' file
# 指定行の前後に行を挿入
sed -i.bak '/^pattern/i\
inserted line before' file
# YAML の値だけ書き換え(key: の後ろ)
sed -i.bak -E 's/^(version:\s*).*/\1"1.2.3"/' config.yaml比較: sed と awk / grep の使い分け
| 用途 | 推奨 |
|---|---|
| 単純な文字列置換 | sed |
| 行抽出(grep 互換) | grep / sed -n |
| 列単位の処理(カラム抽出・計算) | awk |
| 複数行にまたがる変換 | sed の N コマンド or awk |
| 構造化データ(JSON/YAML)の編集 | jq / yq |
sed の強み: ストリーミング 1 行処理、軽量、ほぼすべての Unix で利用可能 sed の限界: 列処理・構造化データ・多行処理が苦手。複雑になったら awk / jq に切り替える