1. ホーム
  2. Linux

【Linux】sed コマンドの使い方|文字列の置換・行の削除・抽出を解説

Share

sed は「ストリームエディタ(stream editor)」の略で、ファイルや入力テキストを1行ずつ読みながら、置換・削除・抽出といった編集を自動で行うコマンドです。エディタを開かずに「この文字列を一括で置き換える」「特定の行だけ抜き出す」といった作業ができるため、設定ファイルの書き換えやログの整形で重宝します。この記事では、もっともよく使う置換を中心に、行の削除・抽出、複数の処理をまとめて行う方法、そしてファイルを直接書き換える -i オプションの注意点までを、コピーして試せる例とともに解説します。

基本の形は s コマンドによる置換

sed でもっとも使うのが文字列の置換です。s/置換前/置換後/ という形(s は substitute の略)で書きます。まずは echo で渡した文字列を置き換えてみましょう。

terminal
# apple を orange に置き換える
$ echo 'I like apple' | sed 's/apple/orange/'
I like orange

# ファイルの内容を置換して画面に表示(ファイル自体は変わらない)
$ sed 's/apple/orange/' fruits.txt

ここで大切なのは、sed は既定では元のファイルを変更しないという点です。処理した結果を画面(標準出力)に表示するだけなので、安心して試せます。ファイル自体を書き換える方法は後半で説明します。

g フラグで行内のすべてを置換する

既定の s/…/…/ は、各行の最初に一致した1か所だけを置換します。同じ行に複数ある場合、すべてを置き換えるには末尾に g(global)フラグを付けます。

terminal
# g なし:最初の a a だけ置換される
$ echo 'a a a' | sed 's/a/b/'
b a a

# g あり:行内すべてを置換
$ echo 'a a a' | sed 's/a/b/g'
b b b

「置換したはずなのに一部しか変わらない」というときは、たいてい g の付け忘れです。行全体を置き換えたい場面は多いので、g は基本とセットで覚えておくとよいでしょう。大文字・小文字を区別せず置換したい場合は gi のように i フラグを足します。

区切り文字は変えられる

置換の区切りには通常 / を使いますが、置換対象にスラッシュが含まれるとき(パスなど)は、\/ とエスケープが増えて読みにくくなります。実は区切り文字は / 以外でもよくs の直後の文字が区切りとして使われます。パスの置換では #| を使うと見やすくなります。

terminal
# / を区切りにするとエスケープだらけで読みにくい
$ echo '/var/www' | sed 's/\/var\/www/\/home\/user/'
/home/user

# 区切りを # にすると読みやすい
$ echo '/var/www' | sed 's#/var/www#/home/user#'
/home/user

どの文字を区切りにしても動作は同じです。置換したい文字列にスラッシュが多いときは、区切りを変えるだけでぐっと読みやすくなります。

行の削除と抽出

sed は置換以外に、行を削除したり、特定の行だけを抜き出したりもできます。行を削除するのは d(delete)コマンド、指定した行だけ表示するのは -n オプションと p(print)コマンドの組み合わせです。

terminal
# 3行目を削除して表示
$ sed '3d' list.txt

# 2行目から5行目までを削除
$ sed '2,5d' list.txt

# 「error」を含む行だけを削除
$ sed '/error/d' log.txt

# -n で自動表示を止め、p で指定行だけ表示(1〜3行目)
$ sed -n '1,3p' list.txt

# 「error」を含む行だけを抽出(grep のような使い方)
$ sed -n '/error/p' log.txt

-n は「各行を自動で表示する」という sed の既定動作を止めるオプションです。これと p を組み合わせることで、「表示したい行だけを明示的に出す」という抽出ができます。/error/ のようにスラッシュで囲むと、その正規表現に一致する行が対象になります。行番号でも、パターンでも対象を指定できるのが sed の柔軟なところです。

複数の処理をまとめて行う

複数の置換や処理を一度に行いたいときは、-e オプションを並べるか、セミコロン ; でつなげます。設定ファイルの複数箇所を書き換えるときなどに便利です。

terminal
# -e を並べて複数の置換
$ sed -e 's/apple/orange/g' -e 's/banana/grape/g' fruits.txt

# セミコロンでつなげても同じ
$ sed 's/apple/orange/g; s/banana/grape/g' fruits.txt

処理は書いた順に、上の行から適用されていきます。前の置換の結果に、次の置換がさらに適用される点だけ意識しておきましょう。

-i でファイルを直接書き換えるときの注意

ここまではすべて「結果を画面に表示するだけ」で、ファイルは変わりませんでした。ファイル自体を書き換えたいときは -i(in-place)オプションを使います。ただし、これは元に戻せない破壊的な操作なので慎重に扱う必要があります。

terminal
# ファイルを直接書き換える(元の内容は失われる)
$ sed -i 's/apple/orange/g' fruits.txt

# .bak を付けてバックアップを残してから書き換える(安全)
$ sed -i.bak 's/apple/orange/g' fruits.txt
# → fruits.txt が書き換わり、fruits.txt.bak に元の内容が残る

おすすめは、まず -i を付けずに実行して結果を画面で確認し、意図どおりなら -i を付けて書き換える流れです。さらに -i.bak のように拡張子を添えると、書き換え前の内容が .bak ファイルとして残るので、失敗しても元に戻せます。大事なファイルを扱うときは、この一手間をかけると安心です。

なお、-i の書き方には注意が必要です。macOS などに入っている BSD 版の sed では、バックアップ無しでも -i '' のように空の引数が必要で、Linux の GNU 版の sed -i とは書き方が微妙に異なります。環境によって挙動が違う点は頭の片隅に置いておきましょう。

まとめ

sed は、テキストを1行ずつ処理する編集コマンドです。もっともよく使うのは s/前/後/ による置換で、行内すべてを置換するには g フラグを付けます。区切り文字は / 以外にもでき、パスの置換では # が便利です。行の削除は d、抽出は -np の組み合わせで行い、複数の処理は -e やセミコロンでまとめられます。ファイルを直接書き換える -i は破壊的なので、まず -i 無しで確認し、-i.bak でバックアップを残すのが安全です。

参考ページ