3    sed エディタによるファイルの編集

この章では,ed と同じ機能を持ったプログラムである sed ストリーム・エディタについて説明します。 この章で説明されている操作を行うために,ed ライン・エディタの使用方法を知っている必要はありません。 次の各節で,sed エディタについて説明します。

ed と異なる点は,sed はユーザと対話するのではなく,スクリプトと呼ばれるコマンド・リストを使用してファイルの編集を行う点です。 このような編集形式をとるため,sed は次のような作業に最適です。

3.1    sed エディタの概要

sed ストリーム・エディタは,標準入力または指定したファイルから入力を受け取り,コマンド・ファイルまたはコマンド行のコマンドによって入力を変更し,その結果のストリームを標準出力に書き込みます。 2 つ以上の入力ファイルを指定すると,sed は,各ファイルを順番に処理して,その結果を標準出力に連結します。 コマンド・ファイルを指定せずに,sed コマンドオプションも使用しなかった場合,sed は,標準入力を変更せず標準出力にコピーします。 このエディタは,編集中のファイルの 2,3 行をメモリに保持するだけなので,一時ファイルを使用しません。 したがって,編集されるファイルのサイズは,使用可能なディスク・スペースによってだけ制限されます。

sed で使用するコマンド・スクリプトは,エディタを実行する前に作成しておいたファイルでも,また,コマンド・オプションとして入力した一連のコマンドでも,またはその両方でもかまいません。 エディタは,1 回の呼び出しで 99 個までのコマンドしか処理することができません。 このような制約のため,また,かなり複雑な編集作業を実行するために, sed からの出力を sed の別のインスタンス にパイプする必要が生じることがあります。

3.2    sed エディタの実行

sed コマンドの構文は次のとおりです。

sed [ [-n] ] [ [ [-e] ] [script] ] [ [-f script_file] ] [ [source_file1 ] [ [source-file2...] ] ]

表 3-1 に,sed コマンドのフラグを示します。

表 3-1:  sed コマンドのフラグ

フラグ 説明
-e script 文字列スクリプトで指定された編集コマンドを,編集コマンドのスクリプトの終わりに追加する。-e フラグを 1 つだけ使用し,-f フラグを指定しない場合は,-e フラグを省略すると,1 つの script をコマンド行に sed の引数として指定することが可能。
-f script_file script_file を編集スクリプトのソースとして使用する。script_file は,入力に適用される編集コマンドの集合。
-n 通常では標準出力へ書き込まれる情報を抑制する。

-e および -f オプションの表記順は重要です。 通常,sed を実行する前に,必要な編集コマンドを記述したコマンド・ファイルを作成します。sed エディタのコマンド・セットは強力で,ほとんど入力の必要はありません。 コマンド・ファイル内の各コマンドは,個別の行に入力することも,セミコロン ( ; ) を使用して各コマンドを区切り,複数のコマンドを 1 行にタイプすることもできます。 たとえば,次の 2 つのスクリプトは,いずれも .ne.RE,または .RS で始まるすべての行を削除します。

スクリプト 1:

/^\.ne/d
/^\.R[ES]/d
 

スクリプト 2:

/^\.ne/d;/^\.R[ES]/d
 

コマンド・ファイル (次の例では cmdfile) を作成した後,次の例のように sed コマンドを入力します。

$ sed -f cmdfile infile > outfile

このコマンドは,cmdfile に含まれているコマンドを使用して,infile を編集し,出力を outfile に書き込みます。 入力ファイルは変更されません。

短い編集スクリプトの場合には,-e オプションの引数として編集コマンドをコマンド行に入力しても同じジョブを実行できます。

$ sed -e '/^\.ne/d;/^\.R[ES]/d' infile > outfile
 

同一のコマンド行で -e オプションと -f オプションを同時に使用すると,両方のオプションで指定されたすべてのコマンドが実行されます。 実行される順番は,オプションがコマンド行に指定されている順番です。 次に例を示します。

$  echo "s/line/foo/" > sedx
$  echo "Test line" | sed -f sedx -e 's/line/bar/'
Test foo
$  echo "Test line" | sed -e 's/line/bar/' -f sedx
Test bar
 

たとえば,次のように,1 個の sed コマンドに -e オプションと -f オプションを 2 回以上使用することができます。

$ sed -f script1 -e 's/foo/bar/' -f script2 msgs > msgs2
 

sed を実行すると,このエディタは構文のチェックおよび効率をよくするためのコマンドの編成を行いながら,コマンド・スクリプトを読み込んでコンパイルします。 その後,入力ファイルを 1 行ずつパターン・スペースというメモリ領域に読み込みます。 次に,エディタはスクリプトに記述してあるコマンドで指定されたアドレスを,パターン・スペースの行に対して次々に照合させます。 コマンドのアドレスがパターン・スペース内の 1 行または複数行と照合した場合,sed は必ず照合したテキストにその編集コマンドを実行します。 各コマンドはテキストに対して順番に実行されます。 各コマンドで変更した結果は,後続するコマンドの入力として使用されます。 パターン・スペース内の所定の行がそれ以上コマンドと照合しなくなると,sed は出力にその行を書き込み,次の入力を読み込みます。 この処理は繰り返し行われます。 この動作の順序のフローチャートは,図 3-1 のとおりです。sed の動作は,図 2-1 に記載した awk プログラムの動作と非常によく似ています。

図 3-1:  sed 処理の順序

編集コマンドによっては,エディタに他のスクリプト・コマンドをバイパスさせたり,または (それらを削除させることで) ある行の書き込みを禁止させたり,または処理を中断させたりして,編集処理の動作方法を変更するものがあります。

3.3    編集行の選択

sed エディタは,アドレスの照合によって編集する行を識別します。 アドレスは,行番号でもコンテキスト・アドレスでもかまいません。

パターン・デリミタとしてスラッシュ以外の文字を使用したい場合は,最初に使用する際にその文字の前にバックスラッシュを付けることによって可能になります。 たとえば,次の 2 つのパターンは同じものとして解釈されます。

/abc/
\xabcx
 

2 つ目のパターンでは,パターン・デミリタとして x を使用しています。 パターン・デミリタとして使用している文字をリテラル文字として使用したい場合には,前にバックスラッシュを付けます。 たとえば,\x\xyzx は,文字列 xyz と解釈されます。

sed エディタは,第 1 章で説明した基本正規表現に加えて,表 3-2 に示す正規表現も認識します。

表 3-2:  sed で認識される正規表現

正規表現 名称 規則
\n 改行 埋め込まれた改行文字を照合します。
// 空のパターン・デミリタ 直前に指定された正規表現と一致したテキストを照合します。

sed コマンドのなかには,アドレスを受け入れないものがあります。 アドレスを受け入れるコマンドは,指定されるアドレスの数によって次のように異なった動作をします。

注意

2 つのアドレスが指定された場合に,sed が終わりのアドレスと照合する行を見つけられないと,sed はファイルの最初のアドレスからファイルの最後までのすべての行に対して実行されます。

3.4    sed コマンドの要約

sed コマンドは,オプションのアドレスを持つ 1 文字の英字で構成されています。 コマンドのなかには,引数を必要とし,コマンドの動作を変更させる修飾子を受け入れるものがあります。 アドレスと英字の間には,スペースを入れてはなりません。 1 つのコマンドに 2 つのアドレスを使用する場合は,コンマでアドレスを区切ってください。r コマンドと w コマンド,および,s コマンド用の w フラグを使用する場合は,英字と引数の間にスペースが 1 つ必要です。 それ以外では,英字と引数の間にスペースを入れてはなりません。

表 3-3表 3-4,および 表 3-5 では,個々の sed コマンドについて説明し,それぞれの構文を記述します。 これらの表については,次の規約が適用されます。

すべてのオプションの要素を含む s コマンドの例を次に示します。

1,/^$/s/vizier//g
 

この例は,メール・メッセージのヘッダ (1 行目から最初に出現する空白行まで) を処理します。 指定された範囲内の文字列 vizier をすべて削除します。

表 3-3 はテキスト編集および移動の sed コマンドについて説明し,構文を示します。

表 3-3:  テキスト編集および移動のコマンド

コマンド 説明
テキストの追加
[addr1]a\ text[\ text...] addr1 で指定された行の後ろに,指定されたテキスト [脚注 2] を書き込んで出力する。i コマンドを参照。
行の変更
[addr1 [,addr2 ]]c\ text[\ text...] アドレスで指定された行範囲を削除して,指定されたテキスト [脚注 2] を,削除された所に書き込んで出力する。 [脚注 3]
行の削除
[addr1 [,addr2 ]]d 指定された行範囲を削除する。 [脚注 3]
パターン・スペースの最初の行の削除
[addr1 [,addr2 ]]D 最初の改行文字が表れるまでのパターン・スペースのすべてのテキストを,その改行文字を含めて削除する。 パターン・スペースに 1 行しかない場合は,このコマンドにより別の行が入力からパターン・スペースに読み込まれる。 これらの動作の後で,このコマンドは編集コマンドのリスト全体を先頭から再開する。
行の挿入
[addr1 ]i\ text[\ text...] 指定されたテキスト [脚注 2] を,addr1 で指定された行の前に書き込んで出力する。a コマンドを参照。
次の行の読み込み
[addr1 [,addr2 ]]n パターン・スペースの中の,指定された範囲を (削除されていなければ) 書き込んで出力する。 次に,入力から次の行をパターン・スペースに読み込む。
行の結合
[addr1 [,addr2 ]]N

指定された複数の行を,埋め込まれた改行文字を持つ 1 行となるように結合させる。 アドレスが 1 つしか与えられていない場合,このコマンドは指定された行を入力ストリームの次の行と結合する。 アドレスの指定,または文字列置換のためのパターン照合は,埋め込まれた改行文字をまたがって拡張することができる。 照合用に埋め込まれた改行文字を示すには,\n を使用する。

行の表示
[addr1 [,addr2 ]]p 編集処理の実行中に p コマンドが出現した時点で,指定された行範囲を出力に書き込む。 このコマンドは,ファイルのセクションを並べ換えるために使用できる。
パターン・スペースの開始行の表示
[addr1 [,addr2 ]]P 編集処理の実行中に P コマンドが出現した時点で,最初の改行文字が出現するまでのパターン・スペースのすべてのテキストの内容を,その改行文字を含めて出力へ書き込む。
ファイルの読み込みと追加

[addr1]r file

指定されたファイル [脚注 4] を読み込んで,そのファイルの内容を addr1 に続けて出力へ書き込む。
テキストの置換
[addr1 [,addr2 ]]s/expr /string /[flags ]
  指定された行の中から,expr で定義した正規表現と照合する文字列を見つけ出し,その文字列を string と置換する。 このコマンドの動作は,gp,および file フラグで修飾される。expr または string にスラッシュ ( / ) が入っている場合は,バックスラッシュ (s/path/path\/file/) を使用して,文字としてのスラッシュを避ける必要がある。 あるいは,アット符号 ( @ ) または疑問符 ( ? ) などの別のデリミタを使用する。 たとえば,s@path@path/file@ は,pathpath/file に置換する。 [脚注 5]
指定したファイルへの書き込み
[addr1 [,addr2 ]]w file 編集処理の実行中に,w コマンドが出現した時点で指定された行範囲を指定されたファイル [脚注 6] に書き込む。
行番号の表示
[addr1 ]= 指定された行の行番号を出力に書き込む。

表 3-4 はバッファ操作用の sed コマンドについて説明し,構文を示します。

表 3-4:  バッファ操作用コマンド

コマンド 説明
ホールド・エリアからのテキストの取り出し

[addr1[,addr2]]g

[addr1[,addr2]]G

ホールド・エリアの内容が存在する場合は,その内容を addr1addr2 で指定されたパターン・スペースにコピーする。g コマンドは,パターン・スペースの以前の内容を破壊する。G コマンドは,ホールドされたテキストをパターン・スペースの内容に追加する。 改行文字を使用して,以前のテキストと追加されたテキストを分割する。
ホールド・エリアへのテキストの移動

[addr1[,addr2]]h

[addr1[,addr2]]H

パターン・スペースの指定された範囲をホールド・エリアにコピーする。h コマンドは,ホールド・エリアの以前の内容を破壊する。H コマンドは,パターン・スペースのテキストを,ホールド・エリアの内容に追加する。 改行文字を使用して,以前のテキストと追加されたテキストを分割する。
パターン・スペースとホールド・エリアの交換
[addr1 [,addr2 ]]x パターン・スペースの内容とホールド・エリアの内容を交換する。

表 3-5 はフロー制御の sed コマンドについて説明し,構文を示します。

表 3-5:  フロー制御のコマンド

コマンド 説明
範囲の否定(「以外」)
[addr1 [,addr2 ]]!cmd 感嘆符 ( ! ) を指定することによって,sed は,入力ファイルの addr1addr2 で指定された範囲以外の部分に対して,感嘆符に続くコマンドを実行する。
コマンドのグループ化

[addr1[,addr2]]{ nested commands }

左右の中カッコによって,実行するコマンドのグループを囲む。 このコマンドのグループは,addr1addr2 で指定された範囲に対して,1 つのセットとして適用される。 最初のコマンドは,この表で示されているように,左の中カッコの次の行にあってもよいし,中カッコと同じ行にあってもよい。 右の中カッコは 1 行に単独で書かなければならない。 グループは他のグループ内にネストすることができる。
ラベル
:label 分岐コマンドの宛先として使用される,編集コマンドのストリーム内の任意の場所を定義する。 ラベルは最高 8 バイトまでの文字列である。 編集ストリームの各ラベルは,独自のものでなければならない。 詳細は, sed(1) を参照。
分岐
blabel label に指定された編集スクリプトの特定の場所に分岐し,ラベルの次のコマンドを使用して,現在の入力行の処理を続行する。label が省略されている場合は,b コマンドは残りの編集スクリプトをバイパスし,新しい入力行を読み込み,スクリプトの先頭から編集を開始する。
条件付き分岐
tlabel 現在の入力行で,置換が正常終了した場合に,label へ分岐する。 それ以外は,コマンドは分岐しない。 どちらの場合でも,このコマンドにより,置換が実行されたことを示すフラグがクリアされる。 このフラグは,個々の新しい入力行の開始時点でもクリアされる。label が省略されていて,分岐が必要とされる場合は,t コマンドは残りの編集スクリプトをバイパスし,新しい入力行を読み込み,スクリプトの先頭から編集を開始する。
終了
[addr1 ]q 現在の行を出力に書き込み,追加されたまたは読み込まれたテキストを出力に書き込んでから終了する,という規則正しい順で編集を終了する。

3.5    文字列の置換

s コマンドは,入力ファイルの指定された行で文字列を置換します。 エディタは正規表現の expr を満たしている入力ファイルの文字列を見つけた場合は,その文字列を string で指定された文字セットと置換します。string 引数は正規表現ではなく,走査されることも解釈されることもありません。 ただし,次のような例外があります。

フラグを使用して,s コマンドの動作を次のように変更することができます。

これらのフラグは,1 度の s コマンドで使用できます。 組み合わせる場合には,w フラグは,指定するすべてのフラグの最後のフラグとして指定されなければなりません。