まくまくPerlノート
読み込んでいるファイルの内容を直接変更する(書き戻し編集: in-place editing)
2008-03-24

書き戻し編集 (in-place editing) に対応したプログラムを作成する

テキストファイルの内容を置換した結果をファイルに出力する場合、一般的には標準出力に出力した内容をリダイレクトします。

$ ./replace.pl input.txt > output.txt

このとき、同じファイルに書き戻そうとすると、ファイルの内容はおそらく失われてしまいます。

$ ./replace.pl input.txt > input.txt  # 危険!

このようなことをしたい場合は、書き戻し編集 (in-place editing)の仕組みを利用すると、読み込み元のファイルを直接編集することができます。 実行方法は次のような感じになります。

$ ./replace.pl input.txt  # input.txt の内容を直接書き換える

in-place editing の機能を利用したい場合は、特殊変数 $^I と、ダイヤモンド演算子 <> を組み合わせて使用します。 以下の例では、ファイル内の Date: で始まる行を書き換えて、現在の日時を挿入しています。

replace.pl

# Backup file extension for in-place editing.
$^I = '.bak';

my $date = localtime;
while (<>) {
    s/^Date:.*/Date: $date/;
    print;
}

特殊変数 $^I にバックアップファイルの拡張子名を設定すると、ダイヤモンド演算子 (<>) によって処理されるファイルは、print によって直接編集されるようになります。 元のファイルは指定した拡張子が付いたファイル名に置換されて残ります。

コマンドラインから書き戻し編集 (in-place editing) の仕組みを利用する

in-place editing の仕組みは、ワンライナーで -i オプションを付けることでも利用できます。 次のように実行すると、入力ファイル input.txt の内容が直接書き換えられ、元のファイル内容は input.txt.bak という名前のバックアップファイルとして保存されます。

input.txt 内のテキストを置換する(Before → After)

$ perl -i.bak -pe 's/Before/After/g' input.txt
  • オプションの意味
    • -i: 入力ファイル自身に書き戻す。さらに拡張子(上記では .bak)を指定することで元のファイルのバックアップを作成する。
    • -p: すべての行を繰り返し処理する。
    • -e: 実行するプログラムを直接指定する。Windows で実行する場合は、コード部分をダブルクォートで囲む必要がある。

ちなみに、-i オプションを付けずに実行すると、置換結果は入力ファイルに書き戻されず、標準出力に出力されます。 入力ファイル自信を書き換える必要がないのであれば、次のように新規ファイルを作成してしまった方が直観的で簡単ですね。

$ perl -pe 's/Before/After/g' input.txt > output.txt
2008-03-24