sedでファイルの中身を一括置換する方法【Mac/Linux完全対応・正規表現・実用コマンド例集】

2011年6月9日


ファイル内の文字列を一括で置換したい場面は、エンジニアなら頻繁に遭遇します。「設定ファイルのホスト名を一気に変えたい」「ログファイルから特定のパターンをSQL形式に変換したい」「数百ファイルにわたるコードのAPIエンドポイントを書き換えたい」。

そんなとき強力な武器になるのが sed コマンドです。

ただ、sed には厄介な罠があります。MacとLinuxで挙動が異なるため、ネットで拾ったコマンドがそのまま動かないケースが多いのです。

この記事では、sed の基本構文から、Mac(BSD sed)とLinux(GNU sed)の違い、正規表現を使った複雑な置換、複数ファイルの一括処理まで、実際に動作確認したコマンド例とともに解説します。

ターミナルでsedコマンドを実行してファイルを一括置換する様子


この記事で解決できること

  • ✅ sedコマンドの基本的な置換構文を理解できる
  • ✅ Mac(BSD sed)とLinux(GNU sed)の違いを把握して両対応できる
  • ✅ 正規表現を使った高度な置換パターンを習得できる
  • ✅ 複数ファイルを一括置換する方法がわかる
  • ✅ ファイルをバックアップしながら上書き保存できる

動作確認環境: macOS Sequoia 15.x(BSD sed)/ Ubuntu 22.04 LTS(GNU sed 4.8)


sedとは?基本構文を理解する

sed(Stream EDitor)は、入力ストリームに対してテキスト変換を行うUnixコマンドです。ファイルを直接編集するのではなく、標準入力または指定ファイルの内容を処理して標準出力に結果を出します。

基本的な置換構文

sed 's/置換前/置換後/' ファイル名
  • s = substitute(置換)コマンド
  • /置換前/置換後/ = 区切り文字に / を使うのが一般的(変更可能)

フラグ一覧

フラグ 意味
g 行内すべて置換(グローバル) s/foo/bar/g
i 大文字小文字を無視 s/foo/bar/gi
数字 N番目のマッチのみ置換 s/foo/bar/2
p 置換した行を出力(-nと組み合わせ) -n 's/foo/bar/p'

基本的なsedコマンド例

特定文字列を置換して標準出力

# ファイルの内容を確認しながら置換(ファイルは変更しない)
sed 's/old_string/new_string/' sample.txt

行内のすべてのマッチを置換(gフラグ)

# gフラグなし:各行の最初のマッチのみ置換
sed 's/foo/bar/' sample.txt

# gフラグあり:各行のすべてのマッチを置換
sed 's/foo/bar/g' sample.txt

実例:

# 入力
echo "foo is foo and foo" | sed 's/foo/bar/'
# 出力: bar is foo and foo

echo "foo is foo and foo" | sed 's/foo/bar/g'
# 出力: bar is bar and bar

区切り文字を変更する

置換対象にスラッシュ(/)が含まれる場合(URLやパスなど)、区切り文字を変更すると可読性が上がります。

# スラッシュをエスケープする方法(読みにくい)
sed 's/\/usr\/local\/bin/\/opt\/bin/' paths.txt

# 区切り文字を | に変更(すっきり)
sed 's|/usr/local/bin|/opt/bin|' paths.txt

# # でも使える
sed 's#/usr/local/bin#/opt/bin#' paths.txt

sedコマンドの区切り文字変更と基本的な使い方の図解


MacとLinuxでのsedの違い【最重要】

sed を使ううえで最も注意すべき点は、Mac(BSD sed)とLinux(GNU sed)で構文が異なることです。特にファイルを直接書き換える -i オプションの挙動が違います。

-i オプションの違い

環境 バックアップなし上書き バックアップあり上書き
Linux(GNU sed) sed -i 's/old/new/' file sed -i.bak 's/old/new/' file
Mac(BSD sed) sed -i '' 's/old/new/' file sed -i.bak 's/old/new/' file

Linuxでは -i の後にスペース不要ですが、MacではBSD sedの仕様で -i '' のようにバックアップ拡張子を必ず指定(空文字列でも可)する必要があります。

# Linux(GNU sed)でファイルを直接書き換え
sed -i 's/old_string/new_string/g' file.txt

# Mac(BSD sed)でファイルを直接書き換え
sed -i '' 's/old_string/new_string/g' file.txt

Linuxで -i '' と書くとエラーになり、MacでLinux構文を使うとバックアップファイルが作られてしまいます。

正規表現の違い

機能 GNU sed(Linux) BSD sed(Mac)
グループ(BRE) \(\) のみ \(\) のみ
グループ(ERE・-E () ()
拡張正規表現 -E または -r -E のみ
\+(1回以上) 使用可 -E
\w(単語文字) 使用可 未対応の場合あり

両対応する方法

Macでも brew install gnu-sed で GNU sed(gsed)をインストールできます:

brew install gnu-sed

# インストール後、gsed として使用
gsed -i 's/old/new/g' file.txt

# または PATH に追加してデフォルトを置き換える
export PATH="/opt/homebrew/opt/gnu-sed/libexec/gnubin:$PATH"

シェルスクリプトでクロスプラットフォーム対応する場合の書き方:

#!/bin/bash
if [[ "$OSTYPE" == "darwin"* ]]; then
    # Mac
    SED="sed -i ''"
else
    # Linux
    SED="sed -i"
fi

$SED 's/old_string/new_string/g' file.txt

正規表現を使った高度な置換

グループと後方参照

\(\) で囲んだ部分をグループとして、\1\2 で参照できます。

実用例:CSVデータをSQL UPDATE文に変換

入力ファイル(phone.csv):

1,09000000000
2,09000000001
3,09000000002

変換後(目標):

update users set mobile_phone = '090-0000-0000' where id = 1;
update users set mobile_phone = '090-0000-0001' where id = 2;
update users set mobile_phone = '090-0000-0002' where id = 3;

sedコマンド:

sed "s/\([^,]*\),\([0-9]\{3\}\)\([0-9]\{4\}\)\([0-9]\{4\}\)/update users set mobile_phone = '\2-\3-\4' where id = \1;/" phone.csv

正規表現の解説:

パターン 意味 マッチする内容
\([^,]*\) カンマ以外の文字の0回以上の繰り返し(グループ1) 1(ID部分)
\([0-9]\{3\}\) 数字3桁(グループ2) 090
\([0-9]\{4\}\) 数字4桁(グループ3) 0000
\([0-9]\{4\}\) 数字4桁(グループ4) 0000

置換後の \1\4 でそれぞれのグループを参照します。

正規表現グループと後方参照の仕組みを示す図解

拡張正規表現(-Eオプション)

-E オプションを使うと、バックスラッシュなしで正規表現グループや + などを使えます:

# 通常の正規表現(エスケープが必要)
sed 's/\([0-9]\{3\}\)-\([0-9]\{4\}\)-\([0-9]\{4\}\)/(\1) \2-\3/' phones.txt

# 拡張正規表現(-E、読みやすい)
sed -E 's/([0-9]{3})-([0-9]{4})-([0-9]{4})/(\1) \2-\3/' phones.txt

電話番号フォーマット変換の例:

echo "090-1234-5678" | sed -E 's/([0-9]{3})-([0-9]{4})-([0-9]{4})/\1\2\3/'
# 出力: 09012345678

echo "09012345678" | sed -E 's/([0-9]{3})([0-9]{4})([0-9]{4})/\1-\2-\3/'
# 出力: 090-1234-5678

行の先頭・末尾への文字列追加

# 各行の先頭に "- " を追加(Markdownリスト変換)
sed 's/^/- /' items.txt

# 各行末尾にセミコロンを追加(SQL文の終端)
sed 's/$/;/' queries.txt

# 先頭と末尾を同時に操作
sed "s/\(.*\)/'\1'/" strings.txt

特定の行のみ置換

# 3行目だけ置換
sed '3s/old/new/' file.txt

# 2〜5行目だけ置換
sed '2,5s/old/new/g' file.txt

# "START" を含む行から "END" を含む行まで置換
sed '/START/,/END/s/old/new/g' file.txt

# 特定パターンを含む行だけ置換
sed '/pattern/s/old/new/g' file.txt

ファイルを直接書き換える(-iオプション)

バックアップなしで上書き

# Linux
sed -i 's/old/new/g' file.txt

# Mac
sed -i '' 's/old/new/g' file.txt

バックアップを作成してから上書き

# バックアップファイル file.txt.bak を作成してから上書き
# Linux
sed -i.bak 's/old/new/g' file.txt

# Mac(同じ構文でOK)
sed -i.bak 's/old/new/g' file.txt

複数ファイルの一括処理

複数ファイルを直接指定

# Linux
sed -i 's/old/new/g' file1.txt file2.txt file3.txt

# Mac
sed -i '' 's/old/new/g' file1.txt file2.txt file3.txt

ワイルドカードで一括処理

# カレントディレクトリの全.txtファイルを置換
# Linux
sed -i 's/old_host/new_host/g' *.txt

# Mac
sed -i '' 's/old_host/new_host/g' *.txt

findと組み合わせてサブディレクトリも含め一括処理

# ディレクトリ配下のすべての.confファイルを置換(Linux)
find /etc/myapp -name "*.conf" -exec sed -i 's/old_host/new_host/g' {} \;

# +を使うと複数ファイルを一度に渡せる(処理が速い)
find /etc/myapp -name "*.conf" | xargs sed -i 's/old_host/new_host/g'

# Mac対応版
find /etc/myapp -name "*.conf" | xargs sed -i '' 's/old_host/new_host/g'

findとsedを組み合わせてディレクトリ配下のファイルを一括置換する流れ

for文と組み合わせる

注意: for file in $(find ...) はファイル名にスペースが含まれると誤動作します。スペースを含まない環境での簡易用途に限定してください。スペースを含む可能性があるときは -execwhile read を使ってください。

#!/bin/bash
# シンプルな環境向け(ファイル名にスペースがない場合)
for file in $(find . -name "*.yml"); do
    sed -i '' 's/image: myapp:old/image: myapp:new/' "$file"
done

# より安全な書き方(ファイル名にスペースが含まれる場合も対応)
find . -name "*.yml" -exec sed -i '' 's/image: myapp:old/image: myapp:new/' {} \;

実用的なユースケース別コマンド集

URLの一括置換(開発→本番環境切り替え)

# http を https に変更
sed -i '' 's|http://example.com|https://example.com|g' config.txt

# ステージング環境から本番環境に切り替え
sed -i '' 's|staging.example.com|www.example.com|g' *.conf

空行の削除

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

# 空白のみの行も削除
sed '/^[[:space:]]*$/d' file.txt

コメントアウト行の削除

# # から始まるコメント行を削除
sed '/^#/d' file.txt

# ; から始まるコメント行を削除(.ini形式など)
sed '/^;/d' config.ini

前後の空白を除去

# 先頭の空白を削除
sed 's/^[[:space:]]*//' file.txt

# 末尾の空白を削除
sed 's/[[:space:]]*$//' file.txt

# 前後両方削除
sed 's/^[[:space:]]*//; s/[[:space:]]*$//' file.txt

ログファイルの整形

# IPアドレスをマスキング
sed -E 's/([0-9]{1,3}\.){3}[0-9]{1,3}/xxx.xxx.xxx.xxx/g' access.log

# タイムスタンプ部分を除去
sed 's/\[.*\] //' access.log

設定ファイルの値を書き換え

# KEY=VALUE 形式の設定ファイルで特定のキーの値を変更
sed -i '' 's/^MAX_CONNECTIONS=.*/MAX_CONNECTIONS=100/' app.conf

# ポート番号の変更
sed -i '' 's/^PORT=[0-9]*/PORT=8080/' .env

よくある失敗パターンと対処法

Mac で「Invalid command code」エラーが出る

原因: Linux構文をMacのBSD sedで実行した。

# エラーになる(Mac)
sed -i 's/old/new/' file.txt
# sed: 1: "file.txt": invalid command code f

対処法: -i '' と空文字列を指定する。

sed -i '' 's/old/new/' file.txt

置換後に想定外の改行が入る

原因: Macでの -i 後の引数の渡し方の問題。

対処法: sed -i '''' の間にスペースを入れる。または gsed を使う。

バックスラッシュが効かない

原因: シングルクォートの中でバックスラッシュエスケープが解釈されない。

# 意図通りに動かない場合
sed 's/\t/    /' file.txt  # タブを4スペースに変えたい

# 解決策1: $'...' 構文でリテラルのタブを使う
sed "s/$(printf '\t')/    /" file.txt

# 解決策2: Perl を使う(より強力)
perl -pi -e 's/\t/    /g' file.txt

まとめ

sedコマンドの一括置換について解説しました。

  • Mac(BSD sed)とLinux(GNU sed)の最大の違い-i オプションの構文。Macは sed -i ''、Linuxは sed -i と覚えておく
  • 正規表現のグループ\(\) で囲み、後方参照は \1\9 で使える
  • 複数ファイルの一括処理には find | xargs sed の組み合わせが強力
  • 本番ファイルを書き換える前は必ず -i.bak でバックアップを作成する習慣をつける

両環境で使うスクリプトを書く場合は gsed のインストールか OS 判定を入れておくと安心です。


関連記事

CentOSLinux,sed,SQL

Posted by GENDOSU