- 技術 💻
sedコマンドの使い方|置換・削除・挿入の逆引きとmacOSとの違い(実行結果つき)
sedコマンドとは、ファイルや他のコマンドの出力を1行ずつ読み込み、置換・削除・挿入などの編集をして出力するコマンドです。設定ファイルの値を書き換える、ログから必要な範囲だけを取り出す、コメントと空行を取り除く、といった作業をエディタを開かずに1行で行えます。
この記事では、すべての例を「入力ファイル → コマンド → 出力」の3点セットで、GNU sed 4.9 で実際に実行した結果をそのまま載せています。やりたいことから探せる逆引き形式で、つまずきやすい -i(ファイルの直接編集)の注意点、改行を含む置換、CSV を扱うときの限界と awk・Python との使い分け、そしてGNU sed(Linux)と macOS の sed の違いを公式マニュアルをもとに表にまとめました。
sedコマンドの早見表(逆引き)
| やりたいこと | コマンド |
|---|---|
| 各行の最初の1つを置換 | sed 's/old/new/' file |
| すべて置換 | sed 's/old/new/g' file |
| 2番目だけ置換 | sed 's/old/new/2' file |
| 大文字・小文字を無視して置換 | sed 's/old/new/gI' file |
/ を含む文字列を置換 |
sed 's#/usr/local#/opt#' file |
| 3行目だけ置換 | sed '3s/old/new/' file |
| 「pie」を含む行だけ置換 | sed '/pie/s/old/new/' file |
| 2行目だけ表示 | sed -n '2p' file |
| 2〜4行目を表示 | sed -n '2,4p' file |
| BEGIN〜END の範囲を表示 | sed -n '/BEGIN/,/END/p' file |
| 2行目を削除 | sed '2d' file |
| 最終行を削除 | sed '$d' file |
| 空行を削除 | sed '/^$/d' file |
| コメント行と空行を削除 | sed '/^#/d; /^$/d' file |
| 行の後ろに追加 / 前に挿入 / 置き換え | sed '2a text' / sed '2i text' / sed '2c text' |
| 一致した行の行番号 | sed -n '/port/=' file |
| 日付の並べ替え(後方参照) | sed -E 's/([0-9]+)-([0-9]+)-([0-9]+)/\3\/\2\/\1/' |
| 一致した部分を使う | sed -E 's/[0-9]+/[&]/g' |
| カンマを改行に | sed 's/,/\n/g' |
| 改行をカンマに | sed -z 's/\n/,/g' または paste -sd, |
| 前後の空白を削除 | sed -E 's/^[[:space:]]+|[[:space:]]+$//g' |
| ファイルを直接書き換え | sed -i 's/old/new/' file |
| バックアップを残して書き換え | sed -i.bak 's/old/new/' file |
| 変更した行だけ表示 | sed -n 's/old/new/p' file |
| 改行コード CRLF を LF に | sed 's/\r$//' file |
基本の形は sed 'アドレス コマンド' ファイル です。アドレス(行番号やパターン)を省略すると全行が対象になり、結果は画面に出力されます(元のファイルは変わりません)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「sedコマンドの使い方|置換・削除・挿入の逆引きとmacOSとの違い(実行結果つき)」
この記事で使う入力ファイル
# fruits.txt
apple banana apple
Apple pie
cherry apple apple apple
# app.conf
# app settings
host=localhost
port=8080
debug=true
# db
db_host=localhost
db_port=5432
# log.txt
10:00 INFO start
10:01 BEGIN job=42
10:02 step a
10:03 END job=42
10:04 INFO idle
n.txt は line1 〜 line6 の6行、pad.txt は前後に空白やタブがある3行です。
置換する(s コマンド)
最初の1つ・すべて・n番目
$ sed 's/apple/orange/' fruits.txt
orange banana apple
Apple pie
cherry orange apple apple
$ sed 's/apple/orange/g' fruits.txt
orange banana orange
Apple pie
cherry orange orange orange
$ sed 's/apple/orange/2' fruits.txt
apple banana orange
Apple pie
cherry apple orange apple
$ sed 's/apple/orange/2g' fruits.txt
apple banana orange
Apple pie
cherry apple orange orange
g を付けないと、各行の最初の1つだけが置換されます。数字を付けるとその番目だけ、2g のように組み合わせると「2番目以降すべて」になります(2g は GNU の拡張です)。
大文字・小文字を無視する
$ sed 's/apple/orange/gI' fruits.txt
orange banana orange
orange pie
cherry orange orange orange
GNU sed では I と i のどちらでも同じ結果になりました。
区切り文字を変える
$ echo '/usr/local/bin' | sed 's/\/usr\/local/\/opt/'
/opt/bin
$ echo '/usr/local/bin' | sed 's#/usr/local#/opt#'
/opt/bin
$ echo '/usr/local/bin' | sed 's|/usr/local|/opt|'
/opt/bin
パスや URL を置換するときは、# や | を区切りにするとエスケープが不要になり、読みやすくなります。s の直後の1文字が区切りになります。
特定の行・範囲・パターンの行だけ置換
$ sed '3s/apple/orange/' fruits.txt
apple banana apple
Apple pie
cherry orange apple apple
$ sed '2,3s/apple/X/g' fruits.txt
apple banana apple
Apple pie
cherry X X X
$ sed '/pie/s/Apple/Cherry/' fruits.txt
apple banana apple
Cherry pie
cherry apple apple apple
$ sed '/^#/!s/localhost/127.0.0.1/' app.conf | head -3
# app settings
host=127.0.0.1
port=8080
アドレスの後ろに ! を付けると「一致しない行」が対象になります。
一致した部分を使う(&)と、& そのものを書く
$ echo 'id=42 qty=7' | sed -E 's/[0-9]+/[&]/g'
id=[42] qty=[7]
$ echo 'x' | sed 's/x/A \& B/'
A & B
置換後の文字列の中で & は「一致した文字列全体」 を表します。& という文字を入れたいときは \& と書きます。
後方参照(\1)と -E
$ echo '2026-09-28' | sed 's/\([0-9]*\)-\([0-9]*\)-\([0-9]*\)/\3\/\2\/\1/'
28/09/2026
$ echo '2026-09-28' | sed -E 's/([0-9]+)-([0-9]+)-([0-9]+)/\3\/\2\/\1/'
28/09/2026
| 標準(BRE) | -E(ERE) |
|
|---|---|---|
| グループ | \( \) |
( ) |
| 1回以上 | \+(GNU 拡張) |
+ |
| 回数指定 | \{2\} |
{2} |
| OR | バックスラッシュ+縦線(GNU 拡張) | 縦線のみ |
括弧や + を使うときは -E を付けると、バックスラッシュが減って読みやすくなります。-E は GNU sed と macOS の sed の両方で使えます。
大文字・小文字の変換(GNU のみ)
$ echo 'user_name order_id' | sed -E 's/_([a-z])/\U\1/g'
userName orderId
$ echo 'HELLO World' | sed 's/.*/\L&/'
hello world
\U(以降を大文字)と \L(以降を小文字)は GNU sed の拡張です。
変更した行だけ表示する
$ sed -n 's/8080/9090/p' app.conf
port=9090
-n で自動出力を止め、p フラグで置換が起きた行だけを表示します。置換の対象を確かめてから -i で書き換えると安心です。
シェルの変数を使う
$ echo 'price: 100' | sed "s/100/$((100*2))/"
price: 200
$ v='a/b'; echo 'x' | sed "s/x/$v/"
sed: -e expression #1, char 7: unknown option to `s'
$ v='a/b'; echo 'x' | sed "s|x|$v|"
a/b
変数を使うときはダブルクォートで囲みます。変数の中身に区切り文字(ここでは /)が含まれるとエラーになるため、中身に出てこない文字を区切りに選ぶと安全です。
行を表示する(-n と p)
$ sed -n '2p' n.txt
line2
$ sed -n '2,4p' n.txt
line2
line3
line4
$ sed -n '$p' n.txt
line6
$ sed -n '1~2p' n.txt
line1
line3
line5
$ sed -n '/BEGIN/,/END/p' log.txt
10:01 BEGIN job=42
10:02 step a
10:03 END job=42
$ sed -n '/INFO/!p' log.txt
10:01 BEGIN job=42
10:02 step a
10:03 END job=42
| アドレス | 意味 |
|---|---|
2 |
2行目 |
2,4 |
2〜4行目 |
$ |
最終行 |
1~2 |
1行目から2行おき(GNU 拡張) |
/BEGIN/,/END/ |
BEGIN を含む行から END を含む行まで |
/INFO/! |
INFO を含まない行 |
-n を付けずに p を使うと、該当行が2回表示されます。「表示するだけ」なら -n と p をセットで使います。
行番号を表示する
$ sed -n '/port/=' app.conf
3
8
$ sed -n '/port/{=;p}' app.conf
3
port=8080
8
db_port=5432
$ sed = n.txt | sed 'N;s/\n/: /' | head -3
1: line1
2: line2
3: line3
先頭のn行だけ(q で終了)
$ sed 3q n.txt
line1
line2
line3
q はその行を出力して終了するので、大きなファイルでも途中で読み込みをやめられます。
行を削除する(d)
$ sed '2d' n.txt
line1
line3
line4
line5
line6
$ sed '2,4d' n.txt
line1
line5
line6
$ sed '$d' n.txt
line1
line2
line3
line4
line5
$ sed '/BEGIN/,/END/d' log.txt
10:00 INFO start
10:04 INFO idle
空行・コメント行を削除する
$ sed '/^$/d' app.conf
# app settings
host=localhost
port=8080
debug=true
# db
db_host=localhost
db_port=5432
$ sed '/^#/d; /^$/d' app.conf
host=localhost
port=8080
debug=true
db_host=localhost
db_port=5432
同じ結果になる書き方を3つ確かめました。
$ sed -e '/^#/d' -e '/^$/d' app.conf # -e で複数のコマンド
$ sed '/^#/d; /^$/d' app.conf # ; で区切る
$ sed -E '/^(#|$)/d' app.conf # 1つの正規表現にまとめる
空白やタブだけの行も消したいときは /^[[:space:]]*$/d と書きます。
行を追加・挿入・置き換える(a / i / c)
$ sed '2a inserted-after' n.txt | head -4
line1
line2
inserted-after
line3
$ sed '2i inserted-before' n.txt | head -4
line1
inserted-before
line2
line3
$ sed '2c replaced-line' n.txt | head -4
line1
replaced-line
line3
line4
パターンと組み合わせると、設定ファイルの編集に便利です。
$ sed '/^port=/c port=9090' app.conf | head -4
# app settings
host=localhost
port=9090
$ sed '/^host=/a timeout=30' app.conf | head -4
# app settings
host=localhost
timeout=30
port=8080
$ sed '$a # end' n.txt | tail -2
line6
# end
複数行を追加する
$ sed '2a\
line-A\
line-B' n.txt | head -5
line1
line2
line-A
line-B
line3
$ sed '2a line-A\nline-B' n.txt | head -5
line1
line2
line-A
line-B
line3
a\ の後に改行して書く形は GNU と macOS の両方で使える書き方です。2a text のように1行で書く形や、テキスト中の \n は GNU の拡張です。
改行を含む置換
$ echo 'a,b,c' | sed 's/,/\n/g'
a
b
c
$ printf 'a\nb\nc\n' | sed ':a;N;$!ba;s/\n/,/g'
a,b,c
$ printf 'a\nb\nc\n' | sed -z 's/\n/,/g'
a,b,c,
$ printf 'a\nb\nc\n' | paste -sd,
a,b,c
sed は1行ずつ処理するため、そのままでは改行を置換できません。:a;N;$!ba は「最終行まで次の行を読み足し続ける」書き方で、全体を1つにまとめてから置換します。-z(GNU 拡張)は入力を NUL 区切りで読むので、最後の改行もカンマになります。改行をカンマに変えるだけなら paste -sd, が最も簡単です。
前後の空白を削除する
cat -A で、行末を $、タブを ^I として見えるようにしています。
$ sed 's/^[[:space:]]*//' pad.txt | cat -A
item-01 $
item-02^I$
item-03$
$ sed 's/[[:space:]]*$//' pad.txt | cat -A
item-01$
^Iitem-02$
item-03$
$ sed -E 's/^[[:space:]]+|[[:space:]]+$//g' pad.txt | cat -A
item-01$
item-02$
item-03$
$ echo 'a b c' | sed 's/ */ /g'
a b c
空白や改行コードを確かめたいときは、sed の l コマンドも使えます。
$ sed -n 'l' pad.txt
item-01 $
\titem-02\t$
item-03$
Windows で作ったファイルの改行(CRLF)は、行末の \r を消すと LF になります。
$ printf 'a\r\nb\r\n' | sed 's/\r$//' | od -c | head -2
0000000 a \n b \n
0000004
ファイルを直接書き換える(-i)
$ sed -i 's/8080/9090/' a1.conf && grep port a1.conf
port=9090
db_port=5432
$ sed -i.bak 's/8080/9090/' a2.conf && ls a2.conf* && diff a2.conf.bak a2.conf
a2.conf
a2.conf.bak
3c3
< port=8080
---
> port=9090
-i は結果を画面に出さず、ファイルそのものを書き換えます。-i.bak のように拡張子を続けて書くと、元のファイルが .bak 付きで残ります。拡張子は -i の直後に空白なしで書きます。
-i で気をつけたいこと
1. GNU sed で -i '' と書くと、スクリプトがファイル名として扱われます。
$ sed -i '' 's/8080/9090/' a4.conf
sed: can't read s/8080/9090/: No such file or directory
-i '' は macOS 向けの書き方です(下の「GNU sed と macOS の違い」を参照)。
2. シンボリックリンクに -i を使うと、リンクが通常のファイルに置き換わります。
$ ln -s a5.conf link.conf
$ sed -i 's/8080/1/' link.conf; ls -l link.conf | awk '{print $1, $NF}'
-rw-r--r-- link.conf
$ grep port= a5.conf
port=8080
db_port=5432
$ ln -s a6.conf link6.conf
$ sed -i --follow-symlinks 's/8080/1/' link6.conf; ls -l link6.conf | awk '{print $1, $NF}'; grep port= a6.conf
lrwxrwxrwx a6.conf
port=1
db_port=5432
-i は新しいファイルを作ってから置き換える仕組みのため、リンク先(a5.conf)は変わらず、link.conf が普通のファイルになりました。リンク先を書き換えたいときは --follow-symlinks(GNU)を付けます。
3. 置換した行を記録しておく
$ sed -i 's/localhost/127.0.0.1/w changes.txt' a1.conf; cat changes.txt
host=127.0.0.1
db_host=127.0.0.1
w ファイル名 フラグで、置換が起きた行を別ファイルに書き出せます。
CSV を扱うときの限界と awk・Python の使い分け
値の中にカンマを含む CSV(2,"note, A4",5)で、2列目を取り出してみます。
$ sed -E 's/^([^,]*),([^,]*),.*/\2/' stock.csv
name
pen
"note
eraser
$ awk -F, '{print $2}' stock.csv
name
pen
"note
eraser
$ python3 -c "import csv; [print(r[1]) for r in csv.reader(open('stock.csv'))]"
name
pen
note, A4
eraser
sed も awk の -F, も、引用符の中のカンマを区別できません。用途に合わせて使い分けると確実です。
| やりたいこと | 向いている道具 |
|---|---|
| 文字列の置換、行の削除・挿入・範囲の取り出し | sed |
| 列(フィールド)ごとの取り出し・集計(引用符なしのデータ) | awk / cut |
| 引用符やカンマを含む本格的な CSV | Python の csv モジュールなど、CSV 用のツール |
デバッグする(--debug)
$ sed --debug 's/a/b/' <<< 'a' | head -8
SED PROGRAM:
s/a/b/
INPUT: 'STDIN' line 1
PATTERN: a
COMMAND: s/a/b/
MATCHED REGEX REGISTERS
regex[0] = 0-1 'a'
PATTERN: b
思いどおりに置換されないときは --debug(GNU sed 4.6 以降)で、どの行にどのコマンドが適用されたかを確かめられます。
GNU sed と macOS(BSD)sed の違い
macOS 側は実行環境がないため未実行で、Apple が公開している sed のマニュアル(sed.1)と FreeBSD の公式マニュアルをもとにまとめています(GNU 側は実行して確認)。
| 項目 | GNU sed(Linux) | macOS sed |
|---|---|---|
バックアップなしで -i |
sed -i 's/a/b/' f |
sed -i '' 's/a/b/' f(拡張子の引数が必要) |
バックアップありで -i |
sed -i.bak ... |
sed -i .bak ... / sed -i.bak ... |
| 拡張正規表現 | -E(-r も可) |
-E(-r も可) |
BRE の \+ \? と OR |
使える(GNU 拡張) | 記載なし(-E で + ? を使う) |
置換後の \n(改行) |
改行になる | バックスラッシュ+実際の改行で書く |
a i c の1行書き(2a text) |
○ | a\ の後に改行して書く |
\U \L(大文字・小文字変換) |
○ | 記載なし |
I フラグ(大文字小文字無視) |
○ | ○ |
-z -s --debug --follow-symlinks |
○ | なし |
アドレス 1~2(n行おき) |
○ | 記載なし |
\t(タブ) |
タブとして扱う | 置換での記載なし($'\t' でタブ文字を渡すと確実) |
GNU sed で macOS の制限に近い動きを確かめるには --posix が使えます。
$ sed --posix 's/a\+/X/' <<< 'aaa'
aaa
--posix では \+ が「1回以上」として扱われず、置換されませんでした。
両方で同じように動かしたいときは、次のように書くと安心です。
- 正規表現は
-Eを付けて+?(){}を使う - ファイルの直接編集は
sed -i.bak '...' file && rm file.bak(拡張子を-iにくっつける形は両方で使えます) - 行の追加は
a\の後に改行して書く - 改行の結合など複雑な処理は
pasteやtr、awk に任せる
macOS でも Homebrew で gnu-sed を入れると、gsed として GNU 版を使えます。
よくある質問
Q. sed で置換したのにファイルが変わりません。
A. sed は通常、結果を画面に出すだけで元のファイルは変えません。ファイルを書き換えるには -i を付けます。まず -i なし(または -n 's/.../.../p')で結果を確かめてから -i を付けるのがおすすめです。
Q. 置換で unknown option to 's' というエラーが出ます。
A. 置換する文字列の中に区切り文字の / が含まれている可能性があります。s#old#new# のように区切り文字を変えるか、\/ とエスケープします。シェル変数を埋め込むときに起きやすいエラーです。
Q. macOS で sed -i を使うとエラーになります。
A. macOS の sed は -i の直後の引数を拡張子として扱います。バックアップが不要なら sed -i '' 's/a/b/' file と空の拡張子を渡します。Linux と共通で使いたいときは sed -i.bak ... の形にします。
Q. sed と awk はどう使い分けますか? A. 行単位の置換・削除・挿入は sed、列ごとの取り出しや合計などの計算は awk が向いています。引用符付きの CSV はどちらも苦手なので、CSV に対応したツールを使うと確実です。
まとめ
- 基本は
sed 's/old/new/g' file。gなしは各行の最初の1つだけ、2なら2番目だけ - アドレスで対象の行を絞る:
3s、2,4d、/BEGIN/,/END/p、/^#/!s - 表示だけなら
-nとpをセットで。-n 's/.../.../p'で置換対象を確かめられる -Eで+()がそのまま使える。&は一致全体、\1は1つ目のグループ-iはファイルを直接書き換える。-i.bakでバックアップ、シンボリックリンクは--follow-symlinks- 改行の結合は
-zやpaste -sd,、引用符付き CSV は CSV 用のツールで - macOS の sed は
-i ''、a\+改行などの違いがあり、両方で動かすなら-Eと-i.bakの形が便利
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「sedコマンドの使い方|置換・削除・挿入の逆引きとmacOSとの違い(実行結果つき)」
株式会社RJCでは、設定ファイルの編集やログの整理といった日々の作業も、コマンドの特徴を確かめながら効率よく進められるよう工夫しています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。