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. 行の抽出#
サンプルデータの textdata ディレクトリにある murphys_law.txt ファイルを用いて sed の使い方を説明します。まず簡単な例として、murphys_law.txt ファイルの 3 行目の内容を出力してみます。3 行目を出力したいので、アドレスを 1、コマンドを p と指定します。
cd ~/Desktop/takarabako/textdata
sed '1p' murphys_law.txt
Smile, tomorrow will be worse.
Smile, tomorrow will be worse.
Every solution breeds new problems.
Everything goes wrong all at once.
Nothing is as easy as it looks.
...
...
Things get worse under pressure.
この実行結果を見ると、1 行目が 2 回出力され、それ以外の行は 1 回ずつ表示されています。これは、何も処理を指定しない場合でも、各行の内容はそのまま出力されるため、そこに 1p の処理が加わることで、1 行目が追加でもう 1 回出力されています。
処理された行のみを出力したい場合は、-n オプションを使用してデフォルト出力を抑制します。
sed -n '1p' 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/g の g は、該当するすべての文字を置換することを意味します。
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 コマンドを使用してください。