🔡

sedコマンドの基本的な使い方メモ

2024/10/11に公開


たまに設定等をシェルスクリプトとして残す際、毎回sedはこういう時どう書けばよかったっけと思うので備忘として残しておきます。個人的な用途特化メモのため厳密性はありません。詳細はmanを参照してください。

前提

環境

$ sed --version
sed (GNU sed) 4.9
Packaged by Debian
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
...
$ cat ./foo.txt
line1-1,line1-2
line2-1,line2-2
line3-1,line3-2
line4-1,line4-2
line5-1,line5-2

$ cat ./bar.txt
bar line1
bar line2

sedのコマンド基本構成

  • sed [オプション] '[編集指示内容]' [入力ファイル]
    • [オプション]
      • -i : [入力ファイル]で指定したファイルを編集結果で置き換える
      • -n : 自動出力しない (基本p指示と一緒に使う)
      • -i.bk : ファイルを置き換え、元ファイルを.bkを付けて保存
      • -E : 対象行指定や編集指示に正規表現が使用可能になる
      • 何も指定しない場合、dry-run (標準出力へ出力)になる
    • [編集指示内容]
      • 文字列として指定する ('str' or "str")
      • 各編集指示はスペースで区切らず連続して記載可能
        • この記事ではわかりやすさのためにスペースで区切る
      • 構成を分解すると大体以下の構成になる
        • [対象行指定] [編集指示]
        • 対象行指定は無い場合がある (全行が対象)
      • 複数の編集指示を行う場合は以下の構成になる
        • [対象行指定] {[編集指示1];[編集指示2];...}
    • [入力ファイル]
      • 編集したいファイル
      • コマンド結果をパイプで渡す場合等、省略可能

ファイル全体の編集

文字列置換

$ sed 's/line/replace/' ./foo.txt
replace1-1,line1-2
replace2-1,line2-2
replace3-1,line3-2
replace4-1,line4-2
replace5-1,line5-2

$ sed 's/line/replace/g' ./foo.txt
replace1-1,replace1-2
replace2-1,replace2-2
replace3-1,replace3-2
replace4-1,replace4-2
replace5-1,replace5-2

$ sed -E 's/line.+/replace/' ./foo.txt
replace
replace
replace
replace
replace

指定キーワード行付近の編集

後に1行挿入

$ sed '/^line3/ a INSERT_LINE' ./foo.txt
line1-1,line1-2
line2-1,line2-2
line3-1,line3-2
INSERT_LINE
line4-1,line4-2
line5-1,line5-2

前に1行挿入

$ sed '/^line3/ i INSERT_LINE' ./foo.txt
line1-1,line1-2
line2-1,line2-2
INSERT_LINE
line3-1,line3-2
line4-1,line4-2
line5-1,line5-2

後に複数行挿入

$ sed '/line3-2$/ a INSERT_LINE1\nINSERT_LINE2' ./foo.txt
line1-1,line1-2
line2-1,line2-2
line3-1,line3-2
INSERT_LINE1
INSERT_LINE2
line4-1,line4-2
line5-1,line5-2

$ cat << EOF | sed '/3-2$/ r /dev/stdin' ./foo.txt
  INSERT_LINE1
  INSERT_LINE2
  INSERT_LINE3
EOF
line1-1,line1-2
line2-1,line2-2
line3-1,line3-2
  INSERT_LINE1
  INSERT_LINE2
  INSERT_LINE3
line4-1,line4-2
line5-1,line5-2

前に複数行挿入

$ sed '/line3/ i \
  INSERT_LINE1\
  INSERT_LINE2\
  INSERT_LINE3' ./foo.txt
line1-1,line1-2
line2-1,line2-2
  INSERT_LINE1
  INSERT_LINE2
  INSERT_LINE3
line3-1,line3-2
line4-1,line4-2
line5-1,line5-2

後にファイル内容挿入

$ sed '/line3/ r ./bar.txt' ./foo.txt
line1-1,line1-2
line2-1,line2-2
line3-1,line3-2
bar line1
bar line2
line4-1,line4-2
line5-1,line5-2

行を丸ごと置き換え

$ sed '/line3/ c REPLACED_LINE' ./foo.txt
line1-1,line1-2
line2-1,line2-2
REPLACED_LINE
line4-1,line4-2
line5-1,line5-2

行削除

$ sed '/line3/ d' ./foo.txt
line1-1,line1-2
line2-1,line2-2
line4-1,line4-2
line5-1,line5-2

2行下を文字列置換

$ sed '/line3/ {n; n; s/line/LINE/g}' ./foo.txt
line1-1,line1-2
line2-1,line2-2
line3-1,line3-2
line4-1,line4-2
LINE5-1,LINE5-2

指定行番号の編集

ファイル先頭に行挿入

$ sed '1 i INSERT_HEAD' ./foo.txt
INSERT_HEAD
line1-1,line1-2
line2-1,line2-2
line3-1,line3-2
line4-1,line4-2
line5-1,line5-2

指定した行範囲で置換

$ sed '2,4 s/line/LINE/g' ./foo.txt
line1-1,line1-2
LINE2-1,LINE2-2
LINE3-1,LINE3-2
LINE4-1,LINE4-2
line5-1,line5-2

その他

スラッシュのある文字列を置換

s///指示の/は任意文字に変更可能。

$ sed '/line3/ s#line#////#g' ./foo.txt
line1-1,line1-2
line2-1,line2-2
////3-1,////3-2
line4-1,line4-2
line5-1,line5-2

インデントのある行を挿入

$ sed '/line3/ c \    LINE_WITH_INDENT' ./foo.txt
line1-1,line1-2
line2-1,line2-2
    LINE_WITH_INDENT
line4-1,line4-2
line5-1,line5-2

特殊文字のエスケープ

基本的にバックスラッシュでエスケープ可能。

$ sed '/line3/ s/line/\&/g' ./foo.txt
line1-1,line1-2
line2-1,line2-2
&3-1,&3-2
line4-1,line4-2
line5-1,line5-2

シングルクオーテーションのエスケープ

編集指示をダブルクオーテーションで囲むのが無難。どうしてもできない場合は特殊なエスケープが必要。

$ sed "/line3/ s/line/line'/g" ./foo.txt
line1-1,line1-2
line2-1,line2-2
line'3-1,line'3-2
line4-1,line4-2
line5-1,line5-2

$ sed '/line3/ s/line/line'\''/g' ./foo.txt
line1-1,line1-2
line2-1,line2-2
line'3-1,line'3-2
line4-1,line4-2
line5-1,line5-2

編集箇所の確認

$ sed -n '2,4 {s/line/LINE/g; p}' ./foo.txt
LINE2-1,LINE2-2
LINE3-1,LINE3-2
LINE4-1,LINE4-2
$ diff ./foo.txt <(sed '2,4 s/line/LINE/g' ./foo.txt)
2,4c2,4
< line2-1,line2-2
< line3-1,line3-2
< line4-1,line4-2
---
> LINE2-1,LINE2-2
> LINE3-1,LINE3-2
> LINE4-1,LINE4-2

参考文献

Discussion