【ワンライナー】ファイルの一括リネームを一行で書く

今回は、いわゆるワンライナーに挑戦してみます。
お題は、前々回の、ファイルをリネームするプログラムです。


Dir.entries('./').reject{|x|/\.$/=~x}.sort_by{|fname|File.stat('./'+fname).mtime}.each_with_index{|fname,index|File.rename('./'+fname,'./railgun'+sprintf('%02d',index+1)+'.xxx')}
まあ、ワンライナーといってもメソッドを繋げているだけなので、難しいところはありません。

利点としては、やはりシェルから実行しやすいことです。
具体的には、シェル(コマンドプロンプト)に

ruby -e 〜〜〜(Rubyのコードをそのまま書く)
と打ち込むことで、〜〜〜の部分のコードを実行することができます。オプション「-e」がキモです。上のプログラムだと、

ruby -e "Dir.entries('./').reject{|x|/\.$/=~x}.sort_by{|fname|File.stat('./'+fname).mtime}.each_with_index{|fname,index|File.rename('./'+fname,'./railgun'+sprintf('%%02d',index+1)+'.xxx')}"
となります。ハマリポイントは、
  • コードを""(二重引用符)で囲むこと
  • %記号は二重にすること
です。

これをバッチファイルとして作成すれば、ワンクリックでRubyのコードを実行することができるというわけです。ハードディスクのファイル整理などにとても役立ちます。


※ただし、今回のようにファイルを直接書き換える処理を記述するときは、大事なファイルに影響が出ないようくれぐれも注意してください!


(追記)間違いを防ぐ方法として、rename部分をputs(fname)で試してみることをおすすめします。SQLでdeleteの前にselectしてみるのと同じ理屈です。その際、バッチファイルからの実行だとウィンドウが一瞬で閉じてしまうので、動体視力に自信のない方は2行目にirbと書いておきましょう。



また、一行化するにあたり、コードを少し修正しています。それについて。

■解説
  • rejectは、delete_ifの非破壊的メソッドです。破壊的メソッドは、オブジェクトに変更がなかった場合(reject!なら、ひとつも削除されなかった場合)、nilを返すので、メソッドチェーンの途中には使用できません。ちなみにreject!とdelete_ifの動きは全く同じです。(※2010/05/08追記:破壊の有無に関わらず、常にオブジェクトを返す破壊的メソッドもあります。delete_ifがそれに該当するため、reject!とは異なる動きをする場合があります。全く同じではありませんでした、すみません)
  • sort_byは、あらかじめソート対象全てをブロック内の値で置き換えてからソートするメソッドです。ただのsortは比較のたびに変換するので、処理速度に大きな差があります。また、結果が変わらないようなので、strftimeするのは止めました。

  • pathは、変数を使わずに直接記述しています('./'の部分)。このままバッチファイルにして実行すると、バッチファイルのあるフォルダのファイルとフォルダ全てがリネームされてしまいます。差し当たり、reject{〜〜〜}を、select{|x|/\.txt$/=~x}に変更すれば、テキストファイルのみが対象となります。

Rubyで日常のPCライフを快適にしてみませんか?


■参考
極めよRuby道 第8回
http://www.notwork.org/~gotoken/mag/cmagazine/gokudo/8th/


コマンドプロンプトを使う - |▽ ̄)ノ なページ再帰