ストリームエディタの sed を使ってみよう

ここからは、テキストファイルの編集や加工に便利なコマンドを紹介していきます。 まず第一弾として、この記事ではストリームエディタの sed(せっど / せど) せっど / せど sed(せっど / せど) を紹介します。

sed はどんなソフトウェアなのか

sed はテキストファイルを編集するためのソフトウェア、つまりテキストエディタです。 Windowsで言えばメモ帳が、Linux Mintならxedが、MX Linuxであれば FeatherPad がテキストエディタの代表です。

  
テキストファイルとは、飾り付けのない文字だけの文書ファイルのことです。 なお、ワープロソフトで作成した文書は図や表を含んでいなくてもテキストファイルとは呼びません。

ただし、sed はそれらのソフトウェアとは使い方が大きく異なります。 一般的なテキストエディタのように対話しながら編集するような設計にはなっていません

編集したい箇所に文字カーソルを移動させ、キーボードから新たな文字を入力したり、Deleteキーで削除したり、という操作は行いません。 そもそも文字カーソルすら sed には存在しません。

sed は "編集したい内容をスクリプトと呼ばれる命令によって与える" という設計のテキストエディタです。 "指示書を与えてテキストファイルを処理させる" という感覚が近いかもしれません。

  
名前の由来は "Stream EDitor" です。

指示書であるスクリプトには色々な命令を記述することができます。 例えば、

  1. 1行目から3行目を削除しなさい
  2. 数字で始まる行だけ抜き出しなさい
  3. "山田" を含む行の "たろう" を "太郎" に置換しなさい

のような指示を与えることができます。 sed はその指示に従ってテキストファイルを編集し、結果を標準出力(つまり画面)に出力します。

サンプルテキストファイルを作る

まずは、sed で編集するためのテキストファイル sample.txt を用意しましょう。 今回は cat コマンドで sample.txt を作ります。

cat コマンドはテキストファイルの中身を表示させるためのコマンドですが、ファイル名を省略すると標準入力(つまりキーボード)から読み込みます。 これをシェルの機能であるリダイレクトを使うことで sample.txt に出力します。

では、キーボードから以下を入力してくださいなお、以下を入力し終えてもキーボードからの入力待ちのままになりますが大丈夫です


cat > sample.txt
ここが始まりの1行目です。
2行目です。
3行目でございます。
4行目です。
最終行です。

以下のようにキーボードからの入力が可能な状態になります。 なお、キーボードからの入力待ちのままでシェルプロンプトに戻っていません

taro@myhostname:~$ cat > sample.txt
ここが始まりの1行目です。
2行目です。
3行目でございます。
4行目です。
最終行です。
 

なぜ、この段階でキーボードからの入力待ちなのかというと、cat コマンドが標準入力からの読み込みを継続しているからです。 cat コマンドはEOF(ファイルの終わり)を読み込むまでは終了しません。

つまり、cat コマンドを終了させるにはEOFを読み込ませる必要があるのです。 過去の記事でも解説しましたが、EOFはCTRL-Dのことです。 キーボードからCTRL+Dキーを押してください

以下のようにcat コマンドが終了し、シェルプロンプトに戻ってきました。

taro@myhostname:~$ cat > sample.txt
ここが始まりの1行目です。
2行目です。
3行目でございます。
4行目です。
最終行です。
taro@myhostname:~$

ファイル名を省略して cat コマンドを実行した場合は、このようにCTRL+Dキーで終了させる必要があります。

ではここで、ファイル sample.txt の中身を確認しておきましょう。 キーボードから cat sample.txt と入力して、Enterキーを押してください。


cat sample.txt

 

以下のようにキーボードから入力した全5行のテキストが書き込まれていることが確認できます。

taro@myhostname:~$ cat sample.txt
ここが始まりの1行目です。
2行目です。
3行目でございます。
4行目です。
最終行です。
taro@myhostname:~$

これで sample.txt の準備ができました。 このファイルを使って sed を勉強していきましょう。

まずは3行目を消してみよう

まずは簡単な編集からやってみましょう。 ここでは3行目だけを削除してみます。

キーボードから sed -e '3d' sample.txt と入力して、Enterキーを押してください。


sed -e '3d' sample.txt

 

以下のように3行目だけが削除されます。

taro@myhostname:~$ sed -e '3d' sample.txt
ここが始まりの1行目です。
2行目です。
4行目です。
最終行です。
taro@myhostname:~$

みなさんの予想通りに '3d' がスクリプトで、"3行目を消しなさい" という意味になります。 オプションの -e は、次に続くものがスクリプトであることを示すものです。 最後の sample.txt はもちろん編集対象のファイル名です。

なお、スクリプトが1つで、かつ、ファイル名を最後に指定する場合に限り、オプションの -e は省略できます。 やってみましょう。

キーボードから sed '3d' sample.txt と入力して、Enterキーを押してください。


sed '3d' sample.txt

 

以下のように同じく3行目が削除されます。 結果は変わりません。

taro@myhostname:~$ sed '3d' sample.txt
ここが始まりの1行目です。
2行目です。
4行目です。
最終行です。
taro@myhostname:~$

このようにスクリプトが1つで、かつ、ファイル名を最後に指定する場合はオプションの -e を省略することができます。


ではここで、ファイル名を省略して sed を利用してみましょう。 ファイル名を省略した場合には、標準入力から読み込まれたテキストが処理されます。 つまり、パイプラインで sed にテキストを渡せるのです。

キーボードから cat sample.txt | sed '3d' と入力して、Enterキーを押してください。


cat sample.txt | sed '3d'

 

以下のように結果は変わりません。

taro@myhostname:~$ cat sample.txt | sed '3d'
ここが始まりの1行目です。
2行目です。
4行目です。
最終行です。
taro@myhostname:~$

このようにパイプラインで sed にテキストを渡すこともできます。

"ファイル名を省略すると標準入力から読み込まれたテキストが処理される" というのであればリダイレクトでもテキストを渡せそうです。 やってみましょう。

キーボードから sed '3d' < sample.txt と入力して、Enterキーを押してください。


sed '3d' < sample.txt

 

以下のようにこれまた結果は同じです。

taro@myhostname:~$ sed '3d' < sample.txt
ここが始まりの1行目です。
2行目です。
4行目です。
最終行です。
taro@myhostname:~$

このようにリダイレクトで sed にテキストを渡すこともできます。

スクリプトの書式

ではここで、スクリプトの書式について説明しておきます。 前出のスクリプトの '3d' を眺めればなんとなくわかると思いますが、スクリプトは、

  1. 範囲指定
  2. コマンド

という構成になっています。 前出のスクリプト '3d' であれば "3" が範囲指定で "d" がコマンドです。 間に空白を入れる必要はありません

  
d コマンドは "Delete" から連想して覚えましょう。

なお、コマンドによっては引数を取るため、

  1. 範囲指定
  2. コマンド
  3. コマンド引数

となることもあります。

いろんな範囲指定を試しみよう

続いて、スクリプトの範囲指定について少し掘り下げてみます。 範囲指定には行番号だけでなく、パターンを指定することもできます。 なお、行番号とパターンを組み合わせることもできます。

まずは、パターンを利用した範囲指定をやってみましょう。 キーボードから sed '/行目/d' sample.txt と入力して、Enterキーを押してください。


sed '/行目/d' sample.txt

 

以下のように "行目" を含む行が全て削除されます。

taro@myhostname:~$ sed '/行目/d' sample.txt
最終行です。
taro@myhostname:~$

このように /(スラッシュ) でテキスト囲むことで、そのテキストを含む行だけを対象にすることができます。

続いてもパターンを利用した範囲指定をしてみますが、今度はちょっと複雑です。 キーボードから sed '/^[0-9]/d' sample.txt と入力して、Enterキーを押してください。


sed '/^[0-9]/d' sample.txt

 

以下のように数字で始まる行が全て削除されます。

taro@myhostname:~$ sed '/^[0-9]/d' sample.txt
ここが始まりの1行目です。
最終行です。
taro@myhostname:~$

このようにパターンには細かな条件を指定することができます。 なお、今回のパターンに含まれている "^" や "[0-9]" という記述は "正規表現" と呼ばれるものです

^(キャレット) は行頭と一致し、[0-9] は 0から9の数字に一致します。 つまり "行頭の直後に数字が存在する行(1文字目が数字の行)" に一致します。

  
正規表現はUNIX系OS共通の仕組みで、わかりやすく言えばパターンマッチングの表現手法です。 sed 独自の仕組みではなく、UNIX系OSで利用される様々なコマンドで広く活用されています。
  
正規表現についてはこの記事の最後でもう少し詳しく解説します。

では次に、複数行を指定する範囲指定を行ってみます。 キーボードから sed '2,4d' sample.txt と入力して、Enterキーを押してください。


sed '2,4d' sample.txt

 

以下のように2行目から4行目が削除されます。

taro@myhostname:~$ sed '2,4d' sample.txt
ここが始まりの1行目です。
最終行です。
taro@myhostname:~$

このように ,(カンマ) で区切ることで開始行と終了行を指定することができます。

続いても複数行を範囲指定してみますが、ちょっと変わった行番号指定をしてみます。 ズバリ、最終行の指定です。 キーボードから sed '3,$d' sample.txt と入力して、Enterキーを押してください。


sed '3,$d' sample.txt

 

以下のように3行目から最終行までが削除されます。

taro@myhostname:~$ sed '3,$d' sample.txt
ここが始まりの1行目です。
2行目です。
taro@myhostname:~$

このように $(ドル記号) で最終行を表すことができます。

  
なお "$-1" で最終行の前行を指定する、というようなことはできません。 "/山田/+2" で "山田" を含む行の2行後ろの行、という表現もできません。 できたらいいのになぁ。

範囲指定に関する最後の話題として、行番号とパターンを組み合わせる例を紹介します。 キーボードから sed '/ここが/,3d' sample.txt と入力して、Enterキーを押してください。


sed '/ここが/,3d' sample.txt

 

以下のように "ここが" を含む行から3行目までが削除されます。

taro@myhostname:~$ sed '/ここが/,3d' sample.txt
4行目です。
最終行です。
taro@myhostname:~$

このように行番号とパターンを組み合わせることもできます。

  
もちろん "/ここが/,/4行目/" のようにパターンとパターンを組み合わせることもできます。

複数のスクリプトを指定する

では続いて、複数のスクリプトを指定する例を見ていきましょう。 今回は2つのスクリプトを渡します。

キーボードから sed -e '3d' -e '/最終/d' sample.txt と入力して、Enterキーを押してください。


sed -e '3d' -e '/最終/d' sample.txt

 

以下のように3行目と "最終" を含む行の両方が削除されました。

taro@myhostname:~$ sed -e '3d' sample.txt -e '/最終/d'
ここが始まりの1行目です。
2行目です。
4行目です。
taro@myhostname:~$

このように複数のスクリプトを指定することもできます。 なお、複数のスクリプトを渡す場合には -e オプションは省略できません

コマンドの紹介

これまで d コマンドしか登場していませんが、もちろん他にもコマンドは用意されています。 ここでは他のコマンドについても紹介していきます。

まずは、テキストを置換するための s コマンドです。

  
s コマンドは "Substitute" から連想して覚えましょう。

では、実際にやってみましょう。 キーボードから sed 's/行目/行め/' sample.txt と入力して、Enterキーを押してください。


sed 's/行目/行め/' sample.txt

 

以下のように "行目" が "行め" に置き換えられます。

taro@myhostname:~$ sed 's/行目/行め/' sample.txt
ここが始まりの1行めです。
2行めです。
3行めでございます。
4行めです。
最終行です。
taro@myhostname:~$

このようにコマンドである "s" に続けて、置換前テキストと置換後テキストを記述します。 置換前テキストと置換後テキストの前後および間には区切り文字である /(スラッシュ) を記述します。

なお、s コマンドの標準動作では行内で最初に見つかった置換前テキストだけを置換します。 同じ行に置換前テキストが2つあっても、置換されるのは最初のテキストだけになります。

見つかった2つ目以降のテキストも置換したい場合は、以下のように g オプションを付与する必要があります。

sed 's/行目/行め/g' sample.txt

g オプションを付けることで、行内の一致する全てのテキストが置換されるようになります。

また、s コマンドでは /(スラッシュ) 以外の文字を区切りにすることもできます。 やってみましょう。

キーボードから sed 's#行目#行め#' sample.txt と入力して、Enterキーを押してください。


sed 's#行目#行め#' sample.txt

 

以下のように結果は変わりません。

taro@myhostname:~$ sed 's#行目#行め#' sample.txt
ここが始まりの1行めです。
2行めです。
3行めでございます。
4行めです。
最終行です。
taro@myhostname:~$

このように区切り文字には /(スラッシュ) 以外の文字を使うことができます。 /(スラッシュ) を含むテキストを置換する場合に利用します。

  
コマンドを意味する "s" に続く1文字が区切り文字だと認識されます。

続いて紹介するコマンドは、テキストを追加するための i コマンドです。

  
i コマンドは "Insert" から連想して覚えましょう。

では、テキストの追加を行ってみましょう。 キーボードから sed '/最終行/i\5行目です。' sample.txt と入力して、Enterキーを押してください。

  
\ はバックスラッシュです。 バックスラッシュはUNIX系OSでは \(バックスラッシュ) として正しく表示されますが、Windows では ¥(円マーク) として表示されます。 どちらにしても、日本語キーボードからは ¥(円マーク) で入力します。
  
ウェブ上でのバックスラッシュの表示は、ウェブブラウザによって異なります。 \(バックスラッシュ) として表示するものもあれば ¥(円マーク) として表示されるものもあります。

sed '/最終行/i\5行目です。' sample.txt

 

以下のように "最終行" を含む行の前に "5行目です。" が追加されます。

taro@myhostname:~$ sed 's/行目/行め/' sample.txt
ここが始まりの1行めです。
2行めです。
3行めでございます。
4行めです。
最終行です。
taro@myhostname:~$

このように i コマンドでは一致する行の前にテキストを追加することができます。

なお、i コマンドでは複数行を追加することもできます。 実際にやってみましょう。

キーボードから sed '/最終行/i\5行目です。\ と入力して、Enterキーを押してください。 なお、以下の入力を終えてもキーボードからの入力待ちのままですが問題ありません

  
行末の \ はバックスラッシュです。

sed '/最終行/i\5行目です。\

 

以下のようにキーボードからの入力待ちのままになります。

taro@myhostname:~$ sed '/最終行/i\5行目です。\
>  

入力待ちになっているのは1行目の最後に入力した \(バックスラッシュ) の影響です。 行末が \(バックスラッシュ) だとシェルは複数行の入力を行ってくれます。

  
複数行の入力を待っているのはシェルです。 sed はまだ呼び出されていません。

では続きを入力しましょう。 キーボードから 6行目です。' sample.txt と入力して、Enterキーを押してください。 これでシェルへの入力が完了し、sed が呼び出されます。


6行目です。' sample.txt

 

以下のように "最終行" を含む行の前に "5行目です。" と "6行目です。" が追加されます。

taro@myhostname:~$ sed '/最終行/i\5行目です。\
> 6行目です。' sample.txt
ここが始まりの1行目です。
2行目です。
3行目でございます。
4行目です。
5行目です。
6行目です。
最終行です。
taro@myhostname:~$

このようにスクリプトは複数行に分けて記載することもできます。 行末に \(バックスラッシュ) を入力することでシェルが複数行の入力を行ってくれることを利用しています。


続いて紹介するのは a コマンドです。 こちらもテキストを追加するためのコマンドですが、こちらは一致する行の後ろにテキストを追加します。

  
a コマンドは "Append" から連想して覚えましょう。

では、テキストを後ろに追加してみましょう。 キーボードから sed '/4行目/a\5行目です。' sample.txt と入力して、Enterキーを押してください。


sed '/4行目/a\5行目です。' sample.txt

 

以下のように "4行目" を含む行の後ろに "5行目です。" が追加されます。

taro@myhostname:~$ sed '/4行目/a\5行目です。' sample.txt
ここが始まりの1行目です。
2行目です。
3行目でございます。
4行目です。
5行目です。
最終行です。
taro@myhostname:~$

このように a コマンドでは一致する行の後ろにテキストが追加されます。

なお、a コマンドでも複数行を追加することができます。 i コマンドと同じように、行末に \(バックスラッシュ) を入力することでシェルに複数行を渡します。


続いては r コマンドを紹介します。 これもテキストを追加するためのコマンドで、一致する行の後ろにテキストが追加されます。 ただし、テキストはスクリプト内で指定するのではなく、別ファイルから読み込まれます。

  
r コマンドは "Read" から連想して覚えましょう。

まずは、別ファイル addtional.txt を用意しましょう。 キーボードから echo 'これは別ファイルです。' > addtional.txt と入力して、Enterキーを押してください。


echo 'これは別ファイルです。' > addtional.txt

 

以下のように "これは別ファイルです。" というテキストをファイル addtional.txt へ保存します。

taro@myhostname:~$ echo 'これは別ファイルです。' > addtional.txt
taro@myhostname:~$

では、別ファイル addtional.txt の内容を後ろに追加してみましょう。 キーボードから sed '$raddtional.txt' sample.txt と入力して、Enterキーを押してください。


sed '$raddtional.txt' sample.txt

 

以下のように最終行のさらに後ろに "これは別ファイルです。" が追加されます。

taro@myhostname:~$ sed '$raddtional.txt' sample.txt
ここが始まりの1行目です。
2行目です。
3行目でございます。
4行目です。
最終行です。
これは別ファイルです。
taro@myhostname:~$

このように r コマンドでは一致する行の後ろに別ファイルから読み込んだテキストを追加することができます。


続いて紹介するのは q コマンドです。 このコマンドは処理を中断するためのコマンドで、

  1. ある行数に達したら処理を中断したい
  2. 空行が見つかったら処理を中断したい

のような要望に答えることができます。

  
q コマンドは "Quit" から連想して覚えましょう。

ここでは、"ございます" を含む行が見つかったら中断してみます。 キーボードから sed '/ございます/q' sample.txt と入力して、Enterキーを押してください。


sed '/ございます/q' sample.txt

 

以下のように "ございます" を含む行で処理が中断されました。

taro@myhostname:~$ sed '/ございます/q' sample.txt
ここが始まりの1行目です。
2行目です。
3行目でございます。
taro@myhostname:~$

このように "条件を満たしたら処理を中断させる" ということが行えます。


最後に紹介するコマンドは、印字を行うための p コマンドです。 なお、印字と行ってもプリンタに出力するわけではありません。 標準出力、つまり画面へ出力するためのコマンドです。

  
p コマンドは "Print" から連想して覚えましょう。

ここでは、3行目を印字してみます。 キーボードから sed -e '3p' -e 'd' sample.txt と入力して、Enterキーを押してください。


sed -e '3p' -e 'd' sample.txt

 

以下のように3行目のみが表示されます。

taro@myhostname:~$ sed -e '3p' -e 'd' sample.txt
3行目でございます。
taro@myhostname:~$

見ての通り今回はスクリプトが2つあり、1つ目のスクリプト "3p" で3行目のみが印字され、2つ目のスクリプト "d" で全ての行が削除されました。 結果として、3行目だけが残ったというわけです。

このように、"一部を残して他は削除したい" という場合に便利なコマンドです。

自動印字の抑制オプション -n

コマンドの紹介を終え、ここからはsedのオプションを解説します。 まずは、自動印字の抑制オプション -n を紹介します。 ここでは前出の3行目だけを残す、というスクリプトをちょっと改良してみます。

キーボードから sed -n '3p' sample.txt と入力して、Enterキーを押してください。


sed -n '3p' sample.txt

 

以下のように3行目のみが表示されます。

taro@myhostname:~$ sed -n '3p' sample.txt
3行目でございます。
taro@myhostname:~$

このように明示的に p コマンドで印字している行を除いて印字されなくなりました。 これが自動印字の抑制オプション -n の効果です。 -n オプションは、"一部を残して他は削除したい" という場合に便利です。

では -n オプションを指定しないとどうなるのか見てみましょう。 キーボードから sed '3p' sample.txt と入力して、Enterキーを押してください。


sed '3p' sample.txt

 

以下のように3行目が重複して表示されます。

taro@myhostname:~$ sed '3p' sample.txt
ここが始まりの1行目です。
2行目です。
3行目でございます。
3行目でございます。
4行目です。
最終行です。
taro@myhostname:~$

このように -n オプションが指定されていない状態では、削除されずに残った全てのテキストが自動的に印字されます。

直接編集オプション -i

続いて紹介するのは直接編集オプション -i です。 このオプションを指定すると対象のファイルが編集されます。

ここまで紹介したsedの利用例では、どれも結果が標準出力(画面)に出力されていました。 つまり、sample.txt には一切変更は加えられていませんでした。

そうではなく "ファイルを直接編集してしまいたい" という場面も多いでしょう。 そのためのオプションが -i です。

まずは、新たなサンプルファイル 2ndsample.txt を用意しましょう。 キーボードから echo '新たなサンプルファイルです。' > 2ndsample.txt と入力して、Enterキーを押してください。


echo '新たなサンプルファイルです。' > 2ndsample.txt

 

以下のように "新たなサンプルファイルです。" というテキストをファイル 2ndsample.txt へ保存します。

taro@myhostname:~$ echo '新たなサンプルファイルです。' > 2ndsample.txt
taro@myhostname:~$

これで、新たなサンプルファイル 2ndsample.txt が用意できました。

では -i オプションは使わずに文字列置換してみましょう。 キーボードから sed 's/サンプルファイル/Sample File/' 2ndsample.txt と入力して、Enterキーを押してください。


sed 's/サンプルファイル/Sample File/' 2ndsample.txt

 

以下のように "サンプルファイル" が "Sample File" に置換されます。

taro@myhostname:~$ sed 's/サンプルファイル/Sample File/' 2ndsample.txt
新たなSample Fileです。
taro@myhostname:~$

では、ファイル 2ndsample.txt の内容を確認してみましょう。 キーボードから cat 2ndsample.txt と入力して、Enterキーを押してください。


cat 2ndsample.txt

 

以下のようにサンプルファイル 2ndsample.txt の内容は変化していません

taro@myhostname:~$ cat 2ndsample.txt
新たなサンプルファイルです。
taro@myhostname:~$

このように -i オプションを付けない場合は対象のファイルは変化しません。

では次に -i オプションを指定して実行してみましょう。 キーボードから sed -i.backup 's/サンプルファイル/Sample File/' 2ndsample.txt と入力して、Enterキーを押してください。


sed -i.backup 's/サンプルファイル/Sample File/' 2ndsample.txt

 

以下のように標準出力へは何も出力されなくなりました。

taro@myhostname:~$ sed -i.backup 's/サンプルファイル/Sample File/' 2ndsample.txt
taro@myhostname:~$

では、ファイル 2ndsample.txt の中身はどうなったでしょうか。 キーボードから cat 2ndsample.txt と入力して、Enterキーを押してください。


cat 2ndsample.txt

 

以下のようにサンプルファイル 2ndsample.txt が書き換えられています

taro@myhostname:~$ cat 2ndsample.txt
新たなSample Fileです。
taro@myhostname:~$

このように -i オプションを付けることでファイルを直接編集することができます。

もう少し説明しなければならないことがあります。 それは、"-i.backup" と記述している点です。 "-i" に続けて ".backup" と記述しているのにはどんな意味があるのでしょうか。

"-i" に続けて(空白は挟まずに) ".backup" のようにテキスト記述すると、そのテキストが付与されたファイル名でバックアップが作成されます。

実際に見てみましょう。 キーボードから ls と入力して、Enterキーを押してください。


ls

 

以下のように 2ndsample.txt.backup が作成されています。

taro@myhostname:~$ ls
2ndsample.txt  2ndsample.txt.backup  addtional.txt  sample.txt
taro@myhostname:~$

では、ファイル 2ndsample.txt.backup の内容を表示してみます。 キーボードから cat 2ndsample.txt.backup と入力して、Enterキーを押してください。


cat 2ndsample.txt.backup

 

以下のようにサンプルファイル 2ndsample.txt.backup の内容は 2ndsample.txt のバックアップであることがわかります。

taro@myhostname:~$ cat 2ndsample.txt.backup
新たなサンプルファイルです。
taro@myhostname:~$

なお、どうしてもバックアップを取りたくないという場合には以下のように -i オプションだけを記述します。

sed -i 's/サンプルファイル/Sample File/' 2ndsample.txt

正規表現をちょっとだけ紹介

前述の通り、sed では範囲指定のパターンに "正規表現" を記述することができます。 例えば以下の例では、^(キャレット) は行頭を表し、[0-9] は 0から9の数字を表します。 つまり "数字で始まる行" を意味します。

sed '/^[0-9]/d' sample.txt

このように特殊な一致条件を指定することができる正規表現ですが、もちろんこの2つだけではありません。

以下に、それ以外の正規表現についても掲載します。 なお、正規表現はとても奥が深いため、ここでは簡単なものだけに絞って紹介します。

正規表現 意味
$
(ドル記号)
行末
.
(ピリオド)
任意の1文字
[]
(ブラケット)
[]内のどれか1文字
※[]内の先頭が^だと "以外の文字" となる
*
(アスタリスク)
直前の文字の0回以上の繰り返し

^(キャレット) や $(ドル記号) はどう表すのか

正規表現では ^(キャレット) は行頭を表し、$(ドル記号) は行末を表します。 それなら、^(キャレット) や $(ドル記号) そのものを表現したいときはどうすればいいのでしょうか。

その場合には、^(キャレット) や $(ドル記号) の前に \(バックスラッシュ) を付けます。 \(バックスラッシュ) には "後ろに続く特殊文字の意味を失わせる" という効果があります。

例えば、

\^

という正規表現は、行頭には一致せずに、文字としての ^(キャレット) に一致します

$(ドル記号) の場合も同様に、

\$

と記述することで、文字としての $(ドル記号) に一致させることができます。 行末には一致しません

バックスラッシュをバックスラッシュでエスケープできる

\(バックスラッシュ) には、次に続く特殊文字の効果を打ち消す作用があることがわかりました。 それなら \(バックスラッシュ) そのものを表現するにはどうすればいいのでしょうか。

\(バックスラッシュ) には "後ろの文字の効果を打ち消す" という効果がありますから \(バックスラッシュ) を2つ連続して記述すればよいだけです。 2つ目の \(バックスラッシュ) はただの文字として扱われます

具体的には、

\\

という正規表現で\(バックスラッシュ) 自身に一致することができます

エスケープ処理が必要な特殊文字

\(バックスラッシュ) を付けて "次に続く特殊文字の効果を打ち消す" ことを "エスケープ処理" と呼びます。 エスケープ処理が必要な特殊文字を以下に掲載します。

特殊文字
^
(キャレット)
$
(ドル記号)
.
(ピリオド)
*
(アスタリスク)
[
(左角括弧)
]
(右角括弧)
/
(スラッシュ)
~
(チルダ記号)
\
(バックスラッシュ)
  
上の表には、説明していない特殊文字も含まれています。

正規表現の記述例

正規表現の記述例をいくつか紹介します。 なお、*(アスタリスク)は0回以上の繰り返しであることがポイントです。

記述例 一致する行
^$ 空行
※改行だけの行
太郎$ "太郎" で終わる行
\$$ $(ドル記号) で終わる行
h.t "hat" / "hit" / "hot" などを含む行
[128] "1" または "2" または "8" を含む行
[A-Z] 英大文字を含む行
[^A-Z] 英大文字以外を含む行
[a-zA-Z0-9] 英数字を含む行
[^0-9]$ 数字以外で終わる行
c* どの行にも一致
※0回以上の繰り返しであるため
c...* cで始まる3文字以上の単語を含む行

後方参照(Back Reference)で前方を参照する

正規表現には "後方参照" と呼ばれる便利な仕組みがあります。 なお、英語では "Back Reference" と表記されます。

後方参照とは、すでに出現したパターンを表現するための仕組みです。 つまり "前方を参照する" ということになります。

後方参照で前方を参照する、とは矛盾しているようですが、まあ、日本語訳の問題です。 "逆行参照" とでも訳してくれればわかりやすかったのですけど。


後方参照は、過去に出現した \( と \) で囲まれた部分を参照する仕組みです。 例えば、

sample.txt
  1. aa
  2. ab
  3. ac
  4. ba
  5. bb
  6. ca
  7. cc
  8. za
  9. zz

というテキストのファイルを、

sed -n '/\([abc]\)\1/p' sample.txt

と実行すると、以下のような結果になります。

taro@myhostname:~$ sed -n '/\([abc]\)\1/p' sample.txt
aa
bb
cc
taro@myhostname:~$

"a" または "b" または "c" が2回連続して出現する行が一致しています。 "ab" や "ac"、"ba" などには一致していません

では、詳しく解説します。 今回の正規表現である、

\([abc]\)\1

は、

\([abc]\)

と、

\1

に分けることができます。

まず、

\([abc]\)

の部分ですが、この部分は \( と \) で囲まれています。 \( と \) で囲むことで、後から参照することができるようになります。

なお、この部分に一致するのは \( と \) を除外した '[abc]' という部分、つまり "a" または "b" または "c" の文字となります。

続いての、

\1

ですが、これは "過去に登場した \( と \) に囲まれた部分の一致結果で置き換えなさい" という意味です。

\(バックスラッシュ) に続いての 1 という数字は番号を表しています。 つまり、最初に登場した \( と \) に囲まれた部分を指します。 \2 であれば、2番目に登場した \( と \) で囲まれた部分となります。

なお、

\1

の部分は [abc] に置き換えられるわけではありません一致した結果に置き換えられます

"aa" の行であれば "a" に、"ab" の行でも "a" に置き換えられます。 同様に "cb" の行であれば "c" に置き換えられます。


後方参照はパターンだけでなく、s コマンドの置換前テキストや置換後テキストにも記述することができます。 例えば、

sample.txt
  1. 199912
  2. 200001
  3. 200503
  4. 202008
  5. 202505
  6. 202510

というテキストのファイルを、

sed 's#\(....\)\(..\)#\1年\2月#' sample.txt

と実行すると、以下のような結果になります。

taro@myhostname:~$ sed 's#\(....\)\(..\)#\1年\2月#' sample.txt
1999年12月
2000年01月
2005年03月
2020年08月
2025年05月
2025年10月
taro@myhostname:~$

このように "YYYYMM" を "YYYY年MM月" のように置換することができます。

  
s コマンドの区切りを /(スラッシュ) ではなく #(シャープ) にしているのは見やすさのためです。 /(スラッシュ) と \(バックスラッシュ) が並ぶと見づらいですから。

正規表現をより詳しく知りたい方へ

正規表現をより詳しく知りたい方は、以下を日本語マニュアルを参照ください。

  1. JM ProjectのREGEX
  

sedに関して説明できていないこと

sedに関してまだまだ説明できていないことがあります。 以下でざっくりと解説したいと思います。

y コマンド

まずは y コマンドです。 y コマンドはテキストを文字の単位で変換するためのコマンドです。

なお s コマンドとは異なり、あくまでも文字の単位での変換です。 例えば、

sed 'y/abc/ABC/' inputfile

とすると以下のように変換されます。

変換前 変換後
abc ABC
cat CAt
hat hAt

以下のように "a" は "A" に、"b" が "B" に "c" が "C" に変換されます。 "abc" を "ABC" に変換しようとするわけではありません

変換内容
a → A
b → B
c → C

-f オプション

-f オプションは、スクリプトをファイルに記述する場合に指定します。 例えば、

sed -f scriptfile inputfile

とするとスクリプトをファイル scriptfile から読み込みます。

ホールドバッファ

sed には "ホールドバッファ" と呼ばれる、テキストを格納することができる領域があります。

  
ホールドスペースとも呼ばれます。

この領域は初期状態では空ですが、各種コマンドを利用することでパターンバッファから複製・追加・入れ替えを行うことができます。

なお、パターンバッファとは sed が対象ファイルから行を読み込む際に利用する場所です。

これまで説明していませんでしたが、sed はファイルを行単位に読み込んで処理します。 読み込まれた行が格納されているのがパターンバッファです。 つまり、現在処理中の1行が格納されている領域です。

このパターンバッファのテキストを、ホールドバッファに複製したり、追加したり、入れ替えたりすることができます。 それぞれに対応したコマンドが用意されています。

コマンド 機能
h パターンバッファの内容をホールドバッファへ複製する
H パターンバッファの内容をホールドバッファへ追加する
g ホールドバッファの内容をパターンバッファへ複製する
G ホールドバッファの内容をパターンバッファへ追加する
x パターンバッファとホールドバッファの内容を入れ替える

複数のファイル名を受け取れる

sedは複数のファイル名を受け取ることができます。 例えば、sample.txt と 2ndsample.txt の2つのファイルを処理したければ、

sed 's/行目/行め/g' sample.txt 2ndsample.txt

のように実行します。

  

まとめ

sed はテキストファイルを編集するためのテキストエディタです。 ただし、対話的に操作するのではなく "スクリプト" と呼ばれる指示を与えてファイルを編集させます。

スクリプトは、

  1. 範囲指定
  2. コマンド

という構成になっています。

範囲指定は行番号を指定することも、パターンを指定することもできます。 また、両方を組み合わせて指定することもできます。

範囲指定の例 意味
3 3行目
$ 最終行
3,$ 3行目から最終行
/山田/ "山田" を含む行
1,/山田/ 先頭行から "山田" を含む行まで

なお、パターンには以下のような正規表現を記述することもできます。

正規表現 意味
^
(キャレット)
行頭
$
(ドル記号)
行末
.
(ピリオド)
任意の1文字
[]
(ブラケット)
[]内のどれか1文字
※[]内の先頭が^だと "以外の文字" となる
*
(アスタリスク)
直前の文字の0回以上の繰り返し

なお、^(キャレット) や $(ドル記号) などの特殊文字そのものを表現したい場合には、それらの文字の前に \(バックスラッシュ) を付けます。

また \(バックスラッシュ) を2つ連続して記述することで \(バックスラッシュ) をのものを表現することもできます。

正規表現 意味
\^ ^(キャレット) に一致
\$ $(ドル記号) に一致
\\ \(バックスラッシュ) に一致

正規表現では \( と \) で囲むことで、後から参照できる後方参照の仕組みがあります。 \1 とすることで最初の \( と \) で囲まれた部分に置き換えられます。 同様に \2 とすることで、2番目の \( と \) で囲まれた部分に置き換えることができます。

sed にはテキストを編集するために必要な以下のようなコマンドが揃っています。

コマンド 機能
d 削除する
s 置換する
y 文字の単位で置換する
i テキストを前に追加する
a テキストを後ろに追加する
r ファイルからテキストを読み込む
q 処理を中断する
p 印字する
h パターンバッファの内容をホールドバッファへ複製する
H パターンバッファの内容をホールドバッファへ追加する
g ホールドバッファの内容をパターンバッファへ複製する
G ホールドバッファの内容をパターンバッファへ追加する
x パターンバッファとホールドバッファの内容を入れ替える

sed が理解するオプションには以下のようなものがあります。

オプション 機能
-e 続く引数がスクリプトであることを伝える
-f スクリプトが格納されているファイルを指定する
-n 自動印字を抑制する
-i ファイルを直接編集する
-i.suffix ファイルを直接編集する
※.suffxを付与したファイル名でバックアップを取る

複数のファイルを処理することもできます。 その場合には、

sed 's/行目/行め/g' filename1 filename2

のように記述します。