2.9. sed#

sed は文字列変換を行うためのスクリプト言語の 1 つです。sed は awk と同様に、コマンドや bash などと組み合わせて利用でき、非常に手軽に使えます。ファイルの内容について、特定のパターンを置換したり、特定の行を削除したりといった処理が可能で、簡便でありながら強力な文字列処理機能を備えています。

2.9.1. 基本文型#

sed は基本的に、指定した行(アドレス)に対して指定した処理を行う、という文型をとります。例えば、アドレス 1 に対してコマンド 1 を実行する場合は、次のように記述します。

address1command1

アドレスやコマンドが複数ある場合は、次のように基本文型を繰り返して記述します。

address1command1
address2command2
address3command3

アドレスの指定方法としては、主に数字を用います。例えば 10 行目に対して処理したい場合は、アドレスを 10 と記述します。また、10 行目から 20 行目に対して処理したい場合は、10,20 のように指定します。アドレスは数字だけでなく、正規表現によるパターンマッチでも指定できます。さらに、アドレスを省略することも可能で、その場合はすべての行に対してコマンドが実行されます。

コマンドはアルファベット 1 文字で表されます。例えば、p は出力(他のプログラミング言語の print 関数に相当)、d は現在の行の削除、i は行の挿入、s は文字列の置換を意味します。以下では、具体例を用いてアドレスとコマンドの書き方を説明します。

2.9.2. 使用例#

2.9.2.1. 行の抽出#

samples ディレクトリにある murphys_law.txt ファイルを使って sed の使い方を説明します。まず簡単な例として、murphys_law.txt ファイルの 3 行目の内容を出力してみます。3 行目を出力したいので、アドレスを 3、コマンドを p と指定します。

cd
cd unix4bi/samples
sed '3p' murphys_law.txt 
## Smile, tomorrow will be worse.
## Every solution breeds new problems.
## Everything goes wrong all at once.
## Everything goes wrong all at once.
## Nothing is as easy as it looks.
## ...
## ...
## Things get worse under pressure.

この実行結果を見ると、3 行目が 2 回出力され、それ以外の行は 1 回ずつ表示されています。これは、sed では処理後の文字列がすべて自動的に出力される仕様になっているためです。何も処理を書かない場合でも、各行の内容がそのまま出力されます。そこに 3p の処理が加わることで、3 行目が追加でもう 1 回出力されているのです。

3p のコマンドだけで 3 行目だけを出力したい場合は、sed のデフォルト出力を抑制する必要があります。そのために -n オプションを使用します。

sed -n '3p' murphys_law.txt 
## Everything goes wrong all at once.

同様にして、3 行目から 6 行目までを出力してみます。

sed -n '3,6p' murphys_law.txt 
## Everything goes wrong all at once.
## Nothing is as easy as it looks.
## Anything that can go wrong will go wrong.
## Matter will be damaged in direct proportion to its value

次に、正規表現を使用して行の抽出を行います。murphys_law.txt ファイルのうち、”will” を含む行を出力します。

sed -n '/will/p' murphys_law.txt 
## Smile, tomorrow will be worse.
## Anything that can go wrong will go wrong.
## Matter will be damaged in direct proportion to its value
## If anything simply cannot go wrong, it will anyway.
## If there is a worse time for something to go wrong, it will happen then.

このように -n オプションと p コマンドを組み合わせることで、特定の行を抽出できます。

2.9.2.2. 行の削除#

sed で行を削除するコマンドは d です。例えば、murphys_law.txt の 3 行目から 19 行目までを削除する場合は、次のようにします。この結果、21 行あるファイルのうち、1、2、20、21 行目だけが出力されます。

sed '3,19d' murphys_law.txt 
## Smile, tomorrow will be worse.
## Every solution breeds new problems.
## New systems generate new problems.
## Things get worse under pressure.

次に、sed コマンドをパイプで連結して使います。murphys_law.txt の 6 行目から 14 行目を削除した後、”new” を含む行だけを出力します。

sed '6,14d' murphys_law.txt | sed -n '/new/p'
## Every solution breeds new problems.
## New systems generate new problems.

続いて、行頭に “If” を含む行を削除し、それ以外の行だけを出力する例を示します。この処理は、CSV ファイルのメタデータ行(行頭が “#” で始まる行)を削除する場合などに応用できます。

sed '/^If/d' murphys_law.txt 
## Smile, tomorrow will be worse.
## Every solution breeds new problems.
## ...
## ...
## Things get worse under pressure.

2.9.2.3. 置換#

文字列の置換は s コマンドで行います。まず、murphys_law.txt の最初の 5 行に対して、小文字の “a” を大文字の “A” に置換してみます。s/a/A/gg は、該当するすべての文字を置換することを意味します。

sed '1,5s/a/A/g' murphys_law.txt 
## Smile, tomorrow will be worse.
## Every solution breeds new problems.
## Everything goes wrong All At once.
## Nothing is As eAsy As it looks.
## Anything thAt cAn go wrong will go wrong.
## Matter will be damaged in direct proportion to its value
## If anything simply cannot go wrong, it will anyway.
## ...

最初の 5 行だけが置換されており、6 行目以降は変更されていないことがわかります。置換されていない行を出力したくない場合は、最初に該当行を抽出してから置換します。

sed -n '1,5p' murphys_law.txt | sed "s/a/A/g"
## Smile, tomorrow will be worse.
## Every solution breeds new problems.
## Everything goes wrong All At once.
## Nothing is As eAsy As it looks.
## Anything thAt cAn go wrong will go wrong.

すべての行に対して置換したい場合は、アドレスを省略します。

sed 's/a/A/g' murphys_law.txt 
## Smile, tomorrow will be worse.
## Every solution breeds new problems.
## Everything goes wrong All At once.
## ...
## ...
## Everything tAkes longer thAn you think.
## New systems generAte new problems.
## Things get worse under pressure.

次に、各行の末尾に “;” を付け加えます。行末は正規表現で $ と表されるため、$; に置換します。

sed 's/$/;/g' murphys_law.txt 
## Smile, tomorrow will be worse.;
## Every solution breeds new problems.;
## Everything goes wrong All At once.;
## ...
## ...
## Everything tAkes longer thAn you think.;
## New systems generAte new problems.;
## Things get worse under pressure.;

sed では後方参照も利用できますが、正規表現の説明が必要になるため、ここでは省略します。後方参照は実用性が高いため、時間のあるときに正規表現とあわせて学習するとよいでしょう。

2.9.2.4. 行の挿入#

行の挿入には i および a コマンドを使用します。i は現在の行の前に挿入し、a は現在の行の後に挿入します。murphys_law.txt のうち、”Every” で始まる行の次に “— — — —” を挿入してみます。

sed '/^Every/i --- --- --- ---' murphys_law.txt 
## Smile, tomorrow will be worse.
## --- --- --- ---
## Every solution breeds new problems.
## --- --- --- ---
## Everything goes wrong all at once.
## Nothing is as easy as it looks.
## ...
## ...
## When all else fails, read the instructions.
## --- --- --- ---
## Everything takes longer than you think.
## New systems generate new problems.
## Things get worse under pressure.

なお、macOS を使用している場合は “command i expects \ followed by text” というエラーメッセージが表示されることがあります。これは macOS 標準の sed がこの記法をサポートしていないためです。その場合は gsed をインストールし、sed の代わりに gsed コマンドを使用してください。