sedの後方参照を使った置換を理解する

シス管系女子2の第7話に出てくる sedコマンドの「後方参照」がいまいち理解できなかったので調べてみました。

sedコマンドとは

「Stream EDitor」の略で、「sed スクリプトコマンド ファイル名」で、指定したファイルをコマンドに従って処理し、標準出力へ出力します。ファイル名を省略した場合は、標準入力からのデータを処理します。sedコマンドでは、パイプとリダイレクトを活用するのが一般的です。

【 sed 】コマンド(基礎編)――テキストファイルを編集する:Linux基本コマンドTips(53) - @IT

vimなどのような対話型エディタではなく、コマンドラインのオプションのみで指示。 流れてくるテキストを編集するから「ストリーム(流れの)エディタ」と言います。

主に文字列の置換、抽出、削除などの処理に使われるコマンド。 ちなみにsedコマンドは編集結果を標準出力に出力するので元のファイルは変更しないので、パイプやリダイレクトを組み合わせて使われることが多いです。

置換

後方参照の前にsedコマンドでよく使われる通常の置換処理についてまとめておきます。(細かい話は省略して簡単にまとめます。)

例) sed_test.txtの内容

ABC
ABCABC
ABCABCABC
  • 行頭に出てくる文字列だけ置換

sed "s/置換前/置換後/" ファイル名

$ sed "s/ABC/DEF/" sed_test.txt
DEF
DEFABC
DEFABCABC
  • すべての文字列を置換する場合は末尾にgを付ける

sed "s/置換前/置換後/g" ファイル名

$ sed "s/ABC/DEF/g" sed_test.txt
DEF
DEFDEF
DEFDEFDEF

ちなみにcatコマンドと |パイプラインでつなげてsedコマンドを使っても同じです。

$ cat sed_test.txt | sed "s/ABC/DEF/g"

後方参照

本題で、これは置換前の内容を置換後に引用させるためのものです。 例えばABCの部分を後ろにDEFを付けてABCDEFとしたい場合などに使えます。 具体的にどうするかというと、

  • 引用したい部分を( )で囲む。(拡張正規表現-rオプションを付ける)
    • -rオプションを付けない場合は\(\)で囲んでエスケープすればいいが可読性が少し悪くなる。
  • そうすると、( )で囲った部分を順に\1 \2で参照することができる。
    • ( )が1つなら\1のみ、2つなら\1 \2、3つなら\1 \2 \3...で参照可。
$ sed -r "s/(ABC)/\1DEF/g" sed_test.txt
ABCDEF
ABCDEFABCDEF
ABCDEFABCDEFABCDEF

2箇所参照の場合

$ sed -r "s/(A)(B)/\1D\2E/g" sed_test.txt
ADBEC
ADBECADBEC
ADBECADBECADBEC

上記はAが\1、Bが\2で参照できるようになって、ABC→ADBECと置換されている。

後方参照の理解は少し難易度が高いですが、( )で囲った部分を引用という事がわかれば理解しやすそうです。