Pythonで全ファイルに何かする、たとえば改行コード変換

日常の便利ツールPythonですが、いつもの頻出タスク、「全ファイルに何かする」をやるとき、いちいち書いていた(書きはじめが書きやすすぎて)のですが、あまりにも頻出するので、もういっそ、最小基本パターンを決め、今後書き換えて使う基本形にしようと決めました。

で、2.6以降だと決め込んで書いたのですが、これがけっこう短くなったので、紹介します。コードは「全ファイルの改行コードをCRLFからLFに変換して上書き」の例です。

import sys, os
from itertools import imap #for only 2.x

def iterfiles(basedir):
    for (path, dirs, files) in os.walk(basedir):
        for fn in files:
            yield os.path.join(path, fn)

if len(sys.argv) < 2:
    raise RuntimeError("No folder specified to convert.")

for fpath in iterfiles(sys.argv[1]):
    with open(fpath) as f:
        txt = "\n".join(imap(lambda line:line.rstrip("\r\n"), f))
    with open(fpath, 'wb') as f: # 'b' for windows stdio
        f.write(txt)

ファイルを開くときのwithが効いていますね。行が複数に分かれないので、行挿入で改造するとき安心です。

また、フォルダ以下の対象ファイルを集めるという概念をiterfilesとしてひとくくりにしています。個々のファイルに処理したい内容と分けてあるので、ファイルの集め方だけをカスタマイズするとき、気楽です。やりすぎるとインターフェースのほうがややこしくなるので、このぐらいで十分。

エラー処理、「例外を吐いて補足しない」のは、人が使ったとき適切なエラー報告を受けることができるんで、身内用としては、最小労力で最大効果なのかなと思って、けっこう気に入ってる方法です。

うーん、importしなくてもfunctoolsのpartialやstringの関数が使えたら、lambdaにしなかったんだけどなぁ。2行もimportに増えるよりは、lambdaでいいや、という妥協。もし上のコードが好みじゃない方がいたら、こんなふうにもできますね。

txt = "\n".join(imap(partial(rstrip, "\r\n"), f))