ohtyskの日記

にわかエンジニアの日記

フォルダ内の複数ファイルを一括処理するRubyスクリプト

今日は久々にRubyに触ったのでネタにブログ書いてみる。(はてな記法の練習も兼ねて)

背景

入力ファイル名と出力ファイル名をコマンドライン引数に渡すと入力ファイルを変換して出力ファイルを作るプログラムを作ったのだが、複数のファイルを一回一回手打ちで実行するのもあれなので、一括で変換するスクリプトを書こうと思った。

プログラムを手打ちで実行するやり方はこんな感じ

./hoge.exe infile outfile

仕様

Windows上のプログラムなので、他人のマシンでも使えることを考えるとバッチスクリプトが良かったのかもしれないが面倒臭いのでRubyスクリプトで作ることにした。

呼び出し方はこんな感じにした

./script.rb infolder outfolder

ただし

  • script.rbはcygwin上で呼び出す(おいw)
  • infolderの中には入力ファイルが複数含まれていて、他のファイルがないものとする
  • script.rbとhoge.exeとinfolderは同一フォルダにおく
  • 入力ファイルの拡張子を.in、出力ファイルの拡張子を.outとする
  • カレントフォルダにoutfolderを作成し、変換後の出力ファイルを保存する

とする

方法

Rubyがもともとそんなに使ってないのと久しぶりだったので、簡単な処理もぐぐったり同僚にききながらやり方を調べた。

必要な処理とやり方の表

必要な処理 やり方 参考
コマンドライン引数の使い方 ARGV http://www-section.cocolog-nifty.com/blog/ruby/index.html
フォルダに含まれるファイル一覧を取得 Dir::glob http://www.namaraii.com/rubytips/?%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8%A5%EA#l12
ベースネームを取得 File::basename http://www.namaraii.com/rubytips/?%A5%D5%A5%A1%A5%A4%A5%EB%A5%A2%A5%AF%A5%BB%A5%B9#l19
*1二つの配列を結合 Array::zip http://ref.xaio.jp/ruby/classes/array/zip
外部コマンドの実行 バッククォートで囲む http://doruby.kbmj.com/yablog/20090531/ruby_1

結果

そしてできたスクリプトはこちら。いろいろハードコーディングしてるが・・・

script.rb
#!/usr/bin/ruby
if ARGV.size < 2 then
  exit
end

infolder  = ARGV[0]
outfolder = ARGV[1]

infiles     = Dir::glob("./#{infolder}/*.in")
inbasenames = infiles.map {|infile| File.basename infile, ".in"}
outfiles    = inbasenames.map {|basename| "./#{outfolder}/#{basename}.out"}

infiles.zip(outfiles).each do |inout|
  command = "./hoge.exe #{inout[0]} #{inout[1]}"
  puts command
  `#{command}`
end


自分の環境でちゃんと動いた。

雑感

  • 久々のRubyスクリプトでirbとかで試しつつ2,30分くらいかかった。が多分書き方がいろいろ変だと思うのでやさしく指摘してください。
  • zipがあったのでなんとなくHaskellっぽくかけてうれしかった
  • よく使いそうなはてな記法は使えた
  • 見出しが思ったより見にくいのであとで目立つようにする

*1:最近Haskellにはまってるのであえてzipを使う方法を選んでみた