今回も、前回に引き続き、フィルタコマンドの「sed」について解説していこう。

sedコマンドの引数の指定

sedコマンドは、動作を引数に指定する。この指定には少々慣れが必要であり、初めは意味不明の文字列のように感じられるかもしれない。だが、もちろんその指定にはルールがあり、フォーマットは次のようになっている。

[範囲][関数][引数]

[範囲]は、省略することも可能だ。その場合、関数で指定された動作が全行に対して適用される。

関数は1文字で表され、「a」「b」「c」「d」「D」「g」「G」「h」「H」「i」「l」「n」「N」「p」「P」「q」「r」「s」「t」「w」「x」「y」などがある。また、[引数]を指定するのは、[関数]に置換を指定した場合が多い(テキストの出力、ラベル、ファイルへの出力などで指定することもある)。なお、[範囲]、[関数]、[引数]の間に空白文字は入れず、「デリミタ(区切り文字)」で区切る。

置換の関数「s」

置換(swap)の関数名は「s」だ。この関数が、sedでは最もよく使われるのではないだろうか。典型的な使い方は、次のとおりだ。


% echo a b a b a b | sed 's/a/A/'
A b a b a b
%

「s/a/A/」の部分が置換の指定になっている。sが関数、/はデリミタだ。そしてaが置換前の文字(列)、Aが置換後の文字(列)となる。上記の例では、1つ目の「a」が置換の対象となり、「A」に置換されている。

置換には、さらに「フラグ」という指定も可能だ。フラグとは、3つ目のデリミタの後に指定するもので、「N」「g」「p」「w」「i」「I」などが用意されている。これらのうち、特によく使うのはgだろう。gを指定すると最初の置換対象だけでなく、それ以降の置換対象に対しても置換を実施してくれるようになる。つまり、こういう具合だ。


% echo a b a b a b | sed 's/a/A/g'
A b A b A b
%

sedを使った置換命令の指定の基本は、これだけである。仮に、ファイル名を一括変換したいといった場合、sedを使うと簡単にこなすことができる。例えば、次のような複数のファイルがあったとしよう。


% ls
請求書_No.0121_2016年12月25日.xls
請求書_No.0122_2016年12月25日.xls
請求書_No.0124_2016年12月25日.xls
請求書_No.0126_2016年12月25日.xls
請求書_No.0133_2016年12月25日.xls
請求書_No.0134_2016年12月25日.xls
請求書_No.0135_2016年12月25日.xls
請求書_No.0136_2016年12月25日.xls
%

これらのファイルを使った処理が終わったので、ファイル名に「(処理済み)」という文字列を付け足したいとする。この時、sedコマンドを使うと次のように処理できる。


% for i in *xls
  do
        mv $i $(echo $i | sed 's/請求書/請求書(処理済み)/')
  done
% ls
請求書(処理済み)_No.0121_2016年12月25日.xls
請求書(処理済み)_No.0122_2016年12月25日.xls
請求書(処理済み)_No.0124_2016年12月25日.xls
請求書(処理済み)_No.0126_2016年12月25日.xls
請求書(処理済み)_No.0133_2016年12月25日.xls
請求書(処理済み)_No.0134_2016年12月25日.xls
請求書(処理済み)_No.0135_2016年12月25日.xls
請求書(処理済み)_No.0136_2016年12月25日.xls
%

まず「請求書」という文字列を「請求書(処理済み)」という文字列に置換し、これを指定してmvコマンドでファイル名を変更しているわけだ。

mvコマンドの前にechoコマンドを指定し、実際にどのようなコマンドが実行されているのかを表示させると次のようになる。


% for i in *xls
  do
        echo mv $i $(echo $i | sed 's/請求書/請求書(処理済み)/')
  done
mv 請求書_No.0121_2016年12月25日.xls 請求書(処理済み)_No.0121_2016年12月25日.xls
mv 請求書_No.0122_2016年12月25日.xls 請求書(処理済み)_No.0122_2016年12月25日.xls
mv 請求書_No.0124_2016年12月25日.xls 請求書(処理済み)_No.0124_2016年12月25日.xls
mv 請求書_No.0126_2016年12月25日.xls 請求書(処理済み)_No.0126_2016年12月25日.xls
mv 請求書_No.0133_2016年12月25日.xls 請求書(処理済み)_No.0133_2016年12月25日.xls
mv 請求書_No.0134_2016年12月25日.xls 請求書(処理済み)_No.0134_2016年12月25日.xls
mv 請求書_No.0135_2016年12月25日.xls 請求書(処理済み)_No.0135_2016年12月25日.xls
mv 請求書_No.0136_2016年12月25日.xls 請求書(処理済み)_No.0136_2016年12月25日.xls
%

sedコマンドで処理すればこれで完了だが、もしこれを手動で変更するとなると面倒なことはお察しいただけるだろう。

なお、ここまでの例だと、デリミタ(区切り文字)である「/」は置換に含めることができないように思われるかもしれないが、実はデリミタは好きな文字に変更できる。関数名であるsの後に書いた文字がデリミタとして使われる仕組みになっているからだ。例えば、次のようにsのあとに「,(カンマ)」を指定すれば、「,」がデリミタとして認識され、スラッシュは置換の対象として利用できるようになる。


% echo /a /b /a /b /a /b | sed 's,/a,/A,g'
/A /b /A /b /A /b
%

「置換元と置換先に存在しない文字列をデリミタに使う」というのが、sedコマンドで置換する際の注意点だ。

今回はsedコマンドの置換機能の基本的な使い方を取り上げた。この機能を活用するだけでも結構いろいろなことができるので、ぜひ1度使ってみてほしい。