sed による置換の基本

LinuxBeginner
オンラインで実践に進む

はじめに

テキスト処理でよく行う作業に「検索と置換」があります。ワードプロセッサでは対話的に実行しますが、Linux のコマンドライン環境では、sed を使って同じ処理をスクリプトから非対話的に実行できます。

sed は、テキストを 1 行ずつ処理する非対話型のテキストエディタです。特定のパターンを新しいテキストに置き換える置換処理で特に力を発揮します。エディタを開いて人が同じ変更を繰り返す必要がないため、自動化にも役立ちます。

この実験では、次の内容を学びます。

  1. テキストの置換(s):基本的な検索と置換を実行します。
  2. グローバル置換(g):行内のパターンを最初の 1 か所だけでなく、すべて置き換えます。
  3. カスタム区切り文字の使用:ファイルパスのようにスラッシュを含むテキストを、別の区切り文字で処理します。
  4. バックアップ付きのインプレース編集:バックアップコピーを自動的に作成し、安全にファイルを変更します。

基本的な置換

まず、文字列に対して簡単な置換を行います。単語 World を Linux に変更します。

sed で置換を行うコマンドは s です。

構文は s/Pattern/Replacement/ です。

この形式は非常によく使われるため、sed を「検索と置換のツール」と考える人も多くいます。しかし、sed は実際にはストリームエディタです。置換は、数多くある編集コマンドの中でも特によく使われるものの 1 つです。

次のコマンドを実行して動作を確認します。

echo "Hello World" | sed 's/World/Linux/'

動作の流れ:

  1. echo が Hello World を標準出力に送ります。
  2. パイプ | がこの出力を sed に渡します。
  3. sed がテキストを読み取り、World というパターンを探して Linux に置き換え、結果を出力します。

注意:このコマンドは元の入力を永続的に変更しません。変更後のテキストを画面(標準出力)に表示するだけです。

この違いは、安全なコマンドライン編集の基本です。Unix 系の環境では、まず変換後のストリームを表示し、保存やリダイレクトを行うかどうかを後から選ぶことがよくあります。

グローバル置換

デフォルトでは、sed は各行で最初に見つかった一致箇所だけを置き換えます。

apple apple というテキストで apple を orange に置き換える場合、sed の出力は orange apple になります。

行内のすべての一致箇所を置き換えるには、置換コマンドの末尾に グローバルフラグ(g) を指定します。

ここで重要なのは「各行で」という点です。sed は 1 行ずつ処理するため、g フラグはファイル全体を 1 つの大きなテキストとして扱うのではなく、現在の行に含まれるすべての一致箇所に作用します。

サンプルファイル quote.txt の内容を確認します。

cat quote.txt

出力:I love Coding. Coding is fun.

次に、グローバルフラグを付けずに Coding を Programming に置き換えます。

sed 's/Coding/Programming/' quote.txt

結果:I love Programming. Coding is fun.
2 つ目の Coding は置き換えられていないことに注意してください。

次に、g フラグを追加します。

sed 's/Coding/Programming/g' quote.txt

結果:I love Programming. Programming is fun.
今度は 2 つの Coding がどちらも正常に置き換えられています。

別の区切り文字を使う

標準的な sed の構文では、スラッシュ / を区切り文字として使用します。形式は s/old/new/ です。

ただし、置換対象のテキストにスラッシュが含まれている場合(例:/usr/local/bin のようなファイルパス)、各スラッシュをバックスラッシュでエスケープする必要があります。その場合、コマンドは s/\/usr\/local\/bin/\/bin/ のようになり、読みにくくなります。

sed では、ほぼすべての文字を区切り文字として使用できます。よく使われる代替の区切り文字には、#、:、| があります。

読みやすい区切り文字を選ぶことは、単なる構文上の工夫ではなく、実用的なスキルです。パターンに / が多数含まれる場合は区切り文字を変更すると、コマンドが理解しやすくなり、入力ミスも減らせます。

パスを含むファイルを作成します。

echo "/usr/local/bin" > path.txt

次に、区切り文字として # を使い、/usr/local/bin を /bin に置き換えます。

sed 's#/usr/local/bin#/bin#' path.txt

結果:/bin

区切り文字に # を使用したため、パス内の / は通常のテキストとして扱われます。その結果、コマンドがすっきりして読みやすくなります。

バックアップ付きのインプレース編集

ここまでの sed は、変更内容を画面に表示するだけでした。ファイルを直接変更する「インプレース編集」を行うには、-i オプションを使用します。

ただし、ファイルを直接変更する操作にはリスクがあります。パターンを誤ると、データを失う可能性があります。理想的には、変更前に元のファイルのバックアップを作成します。

-i.bak のように、-i オプションに拡張子を指定するとバックアップを作成できます。

quote.txt を変更し、quote.txt.bak という名前のバックアップを自動的に作成します。

sed -i.bak 's/fun/awesome/' quote.txt

変更後のファイルの内容を確認します。

cat quote.txt

結果:I love Coding. Coding is awesome.

次に、バックアップが存在し、元のテキストが保存されていることを確認します。

ls -l quote.txt.bak
cat quote.txt.bak

結果:I love Coding. Coding is fun.

これは、複数のファイルに対して一括編集を行う際のベストプラクティスです。

バックアップを作成する習慣が重要なのは、非対話型の編集が高速である一方、ミスを取り消しにくいためです。複数のファイルに対してテキスト置換を自動化すると、パターンの小さな誤りがすぐに広がる可能性があります。元のコピーを残しておくことは、簡単に実践できる安全対策です。

まとめ

この実験では、sed によるテキスト置換の基本を学びました。

  1. 置換(s///):テキストの検索と置換に使う標準的なコマンドです。
  2. グローバルフラグ(g):行内にあるパターンのすべての箇所を置き換えます。
  3. カスタム区切り文字:# などの文字を使い、/ を含むパスや URL を安全に処理します。
  4. インプレース編集時のバックアップ(-i.bak):元の内容を保持したまま、安全にファイルを変更します。

これらのスキルを身につけると、複雑なテキスト処理を効率的かつ安全に自動化できるようになります。