単一ファイルを置換する場合
テキストファイル内を全置換するにはsedコマンドでできます。
$ sed -i 's/BEFORE/AFTER/g' FILENAME
s/BEFORE/AFTER/gのsの意味:BEFOREをAFTERに置換するというsedのコマンド。sedコマンドは置換だけではなく、行抽出や削除などいろんな処理ができる。s/BEFORE/AFTER/gのgの意味:BEFOREにマッチした部分をすべて置換する。gがないと、各行で1つ目のみを置換する。1つ目のみでいいケースは少ないから、置換のときはなにも考えずにgを付けるぐらいでもよい。-i: 全置換してファイルを書き換える。-iがないと、置換結果を標準出力するのみで、ファイル書き換えはしない。
例
$ cat test.txt abcdefabc abc $ sed 's/b/B/g' test.txt # 全置換 aBcdefaBc aBc $ sed 's/b/B/' test.txt # 各行1つ目だけ置換 aBcdefabc aBc
バックアップを残したい場合
-i を -i.bak のように拡張子を付けると、ファイル名の最後に.bak を付けた名前で置換前のバックアップを取ってくれます。
ディレクトリ内の全ファイルを置換したい場合
findコマンドとxargsコマンドを併用
カレントディレクトリ内のすべてのファイルを再帰的に探索して、全ファイルを置換するには、findコマンドとxargsコマンドをsedに組み合わせればできます。
$ find . -type f | xargs sed -i 's/BEFORE/AFTER/g'
findコマンドで見つけたファイルをxargsコマンドを使ってsedコマンドに渡します。
findコマンドでファイルを絞ることもできます。
$ find . -type f -name "*.txt" | xargs sed -i 's/BEFORE/AFTER/g'
ただし、この方法は、findコマンドで見つけたファイルをsedコマンドで保存しなおしますので、置換対象の文字列がなかったとしても、タイムスタンプがすべて現在時刻に置き換わります。それが気持ち悪い場合はgrepも併用するとよいです。
grepコマンドも併用
grepコマンドを併用することで、置換対象の文字列があるファイルのみをsedコマンドに渡します。
$ find . -type f -name "*.txt" | grep -rl BEFORE | xargs sed -i 's/BEFORE/AFTER/g'
grepを使う場合で、findでファイルを絞る必要がない場合はfindは不要です。
$ grep -rl BEFORE . | xargs sed -i 's/BEFORE/AFTER/g'
全置換が怖いからバックアップを残したい
sedのバックアップオプション
sedコマンドでバックアップ拡張子を指定すれば、sedコマンドに渡された全ファイルのバックアップが残されます。
$ find . -type f -name "*.txt" | grep -rl BEFORE | xargs sed -i.bak 's/BEFORE/AFTER/g'
この方法は、大量のバックアップファイルが生成されてしまって、後片付けが面倒という問題があります。置換結果の差分を見るのも面倒です。
ディレクトリごとバックアップ
全置換で大量のファイルが更新されるのがちょっと怖いという場合は、置換前にディレクトリごとコピーしてしまって、置換後にディレクトリごとdiffコマンドで見ることが私は多いです。
$ cp -rvp . ../backup $ find . -type f -name "*.txt" | grep -rl BEFORE | xargs sed -i 's/BEFORE/AFTER/g' $ diff -r ../backup .
gitを使っていればバックアップ不要
git管理下にあれば、バックアップとらずに git diff で置換結果を見て、もとにもどしたければ git checkout すればよいです。