sedでファイルを上書き保存

単一ファイルの場合

-i(--in-place)オプションが使えるsedの場合

cygwinのsed(GNU sed 4.1.5版)では,オプション-i(--in-place)を使うと入力ファイルの上書き更新ができる.例として,「filter.propertiesファイルの中の先頭が#で始まる行(コメント行)を削除して上書き」してみよう.今回の場合は以下の通りとなる.ちなみに先頭の$はコマンドプロンプトである.

$ sed -i -e '/^#/d' filter\.properties

または

$ sed --in-place --expression=/^#/d filter\.properties

上書き前のファイルをバックアップとしてとっておくなら-i(--in-place)にバックアップ用の拡張子を指定する.例えば,上書き前のファイルに拡張子.bakをつけて保管する場合は以下の通り.

$ sed -i.bak -e '/^#/d' filter\.properties

または

$ sed --in-place=.bak --expression=/^#/d filter\.properties

このsedを実行すると,filter.propertiesと同じディレクトリに,更新前のファイルのバックアップ(filter.properties.bak)ができる.

-i(--in-place)オプションが使えないsedの場合

-i(--in-place)オプションが使えない場合は以下の通りである.

$ cat filter\.properties|(rm filter\.properties;sed '/^#/d'>filter\.properties)
  1. 書換前のファイル(filter.properties)をcatとパイプで後続のコマンドに渡す
  2. 書換前のファイル(filter.properties)を削除してsedの処理結果を出力(1でのcatの結果をパイプで受取りsedの入力として処理)

更新前のファイルのバックアップをとっておく場合には以下のようになる.

$ cat filter\.properties|(mv filter\.properties filter\.properties.bak;sed '/^#/d'>filter\.properties)

なお,catを使わないで入力リダイレクトを使った場合,cygwinではPermission deniedが発生する.

$ (rm filter\.properties;sed '/^#/d'>filter\.properties)<filter\.properties
    bash: filter\.properties: Permission denied

サブディレクトリ配下の全ファイルを対象とする場合(findとの組合せ)

-i(--in-place)オプションが使えるsedの場合

findと組合せて,カレントディレクトリ以下のサブディレクトリにあるファイルにsedを使って上書きをしてみよう.-execオプションを使い,カレントディレクトリ配下全てのfilter\.propertiesに上書きを行うコマンドは以下の通り.

$ find . -name 'filter\.properties' -exec sed -i -e '/^#/d' {} \;
  1. -nameオプションで処理対象のファイル名を指定
  2. -execオプションで検索結果に実施するコマンドを指定
  3. -execに検索結果を{}で引き渡す

xargsを使っても同じことができる.

$ find . -name 'filter\.properties'|xargs sed -i -e '/^#/d'

-i(--in-place)オプションが使えないsedの場合

-i(--in-place)オプションが使えない場合は,少しややこしいことになる.まず,findコマンドの-execオプションの中ではパイプが使えない.

$ find . -name 'filter\.properties' -exec cat {}|(rm {};sed -e '/^#/d'>{}) \;
bash: syntax error near unexpected token `\;'

whilereadを使って以下のように記述する.

$ find . -name 'filter\.properties'|while read file;do cat $file|(rm $file;sed -e '/^#/d'>$file);done

動作環境

参考