LinuxやMacでよく使われるコマンドにsedがある。テキストデータの置換処理に使われることが多いコマンドだが、sedコマンドはパターンスペースおよびホールドスペースを理解することで、行の入れ替えといった処理も行うことができる。Opensource.comが「How to use the Linux sed command | Opensource.com」において、sedでパターンスペースおよびホールドスペースを理解するためのわかりやすい解説を行っている。既にsedコマンドで置換処理を行っているユーザーが次のステップとして、sedの使い方を学ぶ方法として参考になる。以下、同記事を参考に、sedコマンドを用いた行の入れ替え処理の方法をまとめてみよう。

Opensource.comの記事では、次のテキストをデータをサンプルとして取り上げている。

元のexample.txt

Line one
Line three
Line two

sedコマンドを使って2行目と3行目を入れ替えて、次のデータを作成する方法を説明している。

変換後のデータ

Line one
Line two
Line three

任意にデータを保持するバッファ「ホールドスペース」

sedはテキストファイルからデータを読み込んで1行ごとに「パターンスペース」と呼ばれるバッファに保持する。sedはパターンスペースに対して処理を行い、結果を標準出力へ出力する。

sedにはこれとは別に「ホールドスペース」という任意にデータを保持するためのバッファを持っている。Opensource.comは、次のサンプルでホールドスペースの動作を説明している。

$ sed -n -e '/three/h' example.txt
$ 

上記コマンドは-nが指定されているので、明示的に出力を指定しない限り、sedコマンドの結果は出力されない。/three/と書いてあるので、このパターンが一致するのはexample.txtの2行目だけで、sedのコマンドとしてhが指定されているので一致した行の改行を除くデータがホールドスペースにコピー(上書き)されている。

出力処理を何も行っていないので、ホールドスペースにコピーしたものの、何の変化も起こっていないように見える。しかし、ホールドスペースを理解するためにまずこの段階から説明を行っている。

ホールドスペースからパターンスペースにコピーする

Opensource.comでは、次のステップとして次の2つのサンプルを掲載している。この2つのサンプルは書き方が違うだけで意味は同じだ。

$ sed -n -e '/three/h' -e 'g;p' example.txt

Line three
Line three
$ 
$ sed -n -e '/three/h;g;p' example.txt

Line three
Line three
$ 

こちらの処理は/three/hに加えてg;pが追加されている。gはホールドスペースの内容をパターンスペースにコピーするsedのコマンド、pはパターンスペースの内容を標準出力へ出力するためのsedコマンドだ。

この指定の動作は次のように行ごとに分けて考えると理解しやすい。

  1. 1行目を読み込む。/three/に一致しないのでhは機能しない。ホールドスペースは空のままだが、gがあるのでホールドスペースの空がパターンスペースにコピーされ、pで出力が行われる。このため空行が出力されている。
  2. 2行目を読み込む。/three/に一致するのでhが機能し、データがホールドスペースに読み込まれる。gによってホールドスペースにコピーされた2行目のデータはパターンスペースにコピーされ、pによって出力される。このため2行目は2行目の内容がそのまま出力されている。
  3. 3行目で読み込む。/three/に一致しないのでhは機能しない。ホールドスペースには2行目でコピーした内容がそのまま存在しているので、gによってこれがパターンスペースにコピーされ、pによって出力される。このため3行目の出力が2行目の内容と同じになっている。

このサンプルはホールドスペースとパターンスペースがどのような関係を理解するために役に立つ。

ホールドスペースからパターンスペースに追加する

Opensource.comでは、次のステップとしてgではなくGを使う方法を紹介している。gはホールドスペースからパターンスペースへのコピー(上書き}ではなく、追記を行う。

$ sed -n -e '/three/h' -e 'G;p' example.txt
Line one

Line three
Line three
Line two
Line three
$ 

このサンプルの動作と先程のサンプルの動作を把握できると、ホールドスペースおよびパターンスペースの使い分けをかなり理解することができる。こちらのサンプルも次のように行ごとに分けて考えると理解しやすい。

  1. 1行目を読み込む。/three/に一致しないのでhは機能しない。ホールドスペースは空だが、Gによってパターンスペースへ追記が行われる。パターンスペースには1行目の内容があるので、これに空が追加されることになる。Gでは改行が挟まるので、pによって出力される内容は1行目の内容と空行という2行分になる。
  2. 2行目を読み込む。/three/に一致するのでhが機能し、データがホールドスペースに読み込まれる。Gによってホールドスペースにコピーされた2行目のデータがパターンスペースへ追記される。改行が挟まるので、pによって出力される内容は2行目の内容が2行分ということになる。
  3. 3行目で読み込む。/three/に一致しないのでhは機能しない。ホールドスペースには2行目でコピーした内容がそのまま存在しているので、Gによってこれがパターンスペースへ追記される。改行が挟まるので、pによって出力される内容は3行目の内容と2行目の内容の2行分になる。

ホールドスペースを使って行を入れ替える

Opensource.comでは最後のサンプルとして次のコマンドを取り上げている。

$ sed -n -e '/three/h' -e '/three/d' -e '/two/G;p' example.txt
Line one
Line two
Line three
$ 

この動きも行ごとに分けて考えると理解しやすい。

  1. 1行目を読み込む。どのパターンにも一致せずpが機能して、1行目がそのまま出力される。
  2. 2行目を読み込む。/three/hと/three/dが一致する。/three/hによって2行目の内容がホールドスペースへコピーされる。/three/dによってこの行は削除され、pによる出力は行われない。
  3. 3行目を読み込む。/two/Gが一致する。パターンスペースには3行目の内容が入っているが、Gによってこれにホールドスペースの内容がパターンスペースへ追記される。ホールドスペースには2行目の内容がコピーされている。間に改行が挟まるので、パターンスペースの内容は「3行目\n2行目」のようになり、2行目と3行目が入れ替わった状態で出力が行われる。

このサンプルは簡単な記述だが動作は結構複雑だ。しかし、パターンスペースとホールドスペースの動作を理解する上ではかなりよいサンプルになっている。パターンスペースとホールドスペースを理解すると、sedコマンドで行を入れ替えるといった動作が行えるようになる。

  • サンプルコマンドの実行例

    サンプルコマンドの実行例