スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Rubyほかスクリプト言語について -- ファイル移動のプログラム

ディフェンシブな開発 ~ SIビジネスの致命的欠陥

先日、Rubyについての記事を読むまで正直Rubyについてよくわかっていなかった。スクリプト言語ということで相手にしていなかった部分もある。しかし、最近何かに付けて話題が出てくるのと、国産だが世界に広がっている点、Martin Fowlerが取り上げている点などから自分も注目してみようかと思っている。

スクリプト言語は手軽にプログラムを作るには便利だ。
ちょっと最近、というか今までも時々だが、ファイル移動のスクリプトを作りたいと思っていた。目的は、単純にサブディレクトリ配下のファイルを上のディレクトリに移動してくる、というだけのものだ。ただし、名前のバッティングを避けるために、単純にファイルを移動するのではなく、「ディレクトリ名_ファイル名」とリネームして移動する。たとえば、

(カレントディレクトリ)
  サブディレクトリ1
   ファイル1
   ファイル2
  サブディレクトリ2
   ファイル1
   ファイル2

これを
(カレントディレクトリ)
  サブディレクトリ1_ファイル1
  サブディレクトリ1_ファイル2
  サブディレクトリ1_ファイル1
  サブディレクトリ1_ファイル2

というようにする。簡単に出来そうだが、DOSプロンプトでXCOPYなどを使ったのではできない。今までこういうとき、ファイルリストをファイルに出力して、エディタで編集して、ren xx yyという非常に原始的なやり方をやっていた。そうしょっちゅうあることではないので、一時的にはこれで十分だが、やはりこの辺のスクリプトはさっと作れるようになっておいたほうがいい、と思い、作ってみた。

まずWSHとして、VBScriptを使って作ってみた。たとえば、c:\hoge\movesub.vbsで保存。

対象のなるディレクトリでDOS窓を開いて、
CSCript c:\hoge\movesub.vbs で実行


Set FSO = WScript.CreateObject("Scripting.FileSystemObject") 
Set wshShell = CreateObject("WScript.Shell")
Set curDir = FSO.GetFolder(wshShell.CurrentDirectory)

For Each srcDir In curDir.SubFolders
    For Each tgtFile In srcDir.Files
        WScript.Echo srcDir.Name & "_" & tgtFile.Name
        tgtFile.Move srcDir.Name & "_" & tgtFile.Name
    Next
Next

続いて、DOSコマンドで実行。確かXPだったからか拡張されている。for /?でヘルプを見ながら作成。結局これが一番シンプルだった。


for /D %x in (*.*) do for /F "delims==" %y in ('dir /B %x') do move "%x\%y" "%x_%y"

Perl版。perl c:\hoge\movesub.plで実行。もっと洗練された書き方ができるかも。


use File::Copy;

opendir(curDir, ".");
@dir = readdir(curDir);
closedir(curDir);

foreach (@dir) {
  if (-d $_ && $_ ne "." && $_ ne "..") {
    $x=$_;
    opendir(srcDir, $x);
    @tgtFiles = readdir(srcDir);
    closedir(srcDir);
    foreach (@tgtFiles) {
      if ($_ ne "." && $_ ne "..") {
        $tgtFile = $x."\\"."$_";
        $dstFile = $x."_"."$_";
       move $tgtFile, $dstFile or die $!;
      }
    }
  }
}

同じくPHP版。php c:\hoge\movesub.phpで実行。


<?php
  if ($handle = opendir(".")) {
    while (false !== $srcDir = readdir($handle)) { 
      if($srcDir != "." && $srcDir != "..") { 
        if(is_dir($srcDir)) {
          if ($handle2 = opendir($srcDir)) {
            while (false !== $tgtFile = readdir($handle2)) { 
              if($tgtFile != "." && $tgtFile != "..") { 
                if(!is_dir($tgtFile)) {
                  rename($srcDir."\\".$tgtFile, $srcDir."_".$tgtFile);
                }
              }
            }
            closedir($handle2); 
          }
        }
      }
    } 
    closedir($handle); 
  }
?>

Java版。コンパイルしてから、java -cp c:\hoge MoveSub で実行。


import java.io.*;

public class MoveSub {
  public static void main(String[] args) throws Exception {
    File curDir = new File(".");
    File[] srcDirs = curDir.listFiles();
    for (int i=0; i<srcDirs.length; i++) {
      if (srcDirs[i].isDirectory()) {
        File[] tgtFiles = srcDirs[i].listFiles();
        for (int j=0; j<tgtFiles.length; j++) {
          File dstFile = new File(srcDirs[i].getName() + "_" + tgtFiles[j].getName());
          tgtFiles[j].renameTo(dstFile);
        }
      }
    }
  }
}

慣れているせいか、Javaが一番作るのが早かった。

そしてRuby。いろいろなやり方があったようにみえたが、やりやすそうなのを選択。
ruby c:\hoge\movesub.rbで実行


require 'find'
require 'fileutils'

Find.find('.') {|tgtFile|
  if File.file? tgtFile
    if tgtFile =~ /\.\/.*\/.*/
      dstFile = tgtFile.gsub(/\.\//,"")
      dstFile = dstFile.gsub(/\//,"_")
      FileUtils.mv(tgtFile, dstFile);
    end
  end
}

exit


こうしてみると、それぞれの違いを検討できる。Rubyだけほかのに比べて、置換を行っている分若干ロジックが違うのだが。
Javaはコンパイルが入ったのだが、慣れている分一番早かった。だがこの程度のことでわざわざJavaを使うというのも気が引ける。

この手のプログラム、まあプログラムというほどのものではないが、のレベルだと、DOSプロンプトの拡張だけで十分できてしまう。Unix上だとシェルスクリプトを覚えておけば大体のことは出来るが、Windows上で手軽にできる技術は持っておいたほうがいい。そういえば、cygwin版をやっていなかったな。

何に精通すべきか。

関連記事
スポンサーサイト

コメント

非公開コメント

そういうhappieさんには Monad をおすすめします(笑)



真面目に書くと、まあWindows環境にはVBScriptが一番無難なんじゃないでしょうか。

#もちろんケースバイケースで使い分けられればベストでしょうけど。

WSHでJScript(VBS版と同じメソッド使わない版)



var FSO = new ActiveXObject("Scripting.FileSystemObject");

var curDir = FSO.GetFolder(".");



for(var srcDir = new Enumerator(curDir.SubFolders); !srcDir.atEnd(); srcDir.moveNext()){

for(var tgtFile = new Enumerator(FSO.GetFolder(srcDir.item().Path).Files); !tgtFile.atEnd(); tgtFile.moveNext()){

fn=curDir.Path.replace(/\\/g,"\\\\")+"\\"+srcDir.item().Name+"_"+tgtFile.item().Name;

WScript.Echo(srcDir.item().Name+"_"+tgtFile.item().Name);

FSO.CopyFile(tgtFile.item().Path.replace(/\\/g,"\\\\"),fn);

}

}

Monadって、

<a href="http://japan.cnet.com/news/sec/story/0,2000050480,20086195,00.htm">マイクロソフトの新シェル「Monad」を狙うコードが公開に</a>

このこと? まだ先は長そう。

うーん。こめんとではタグが使えないのか。修正も出来ない。
プロフィール

dayan

Author:dayan
小職は、SE(システムエンジニア)を専門としておりますが、技術的な情報を中心に、それ以外に経済関連の日記、たわいもない日記も載せていきます。
[公式HPもよろしく!]

天気予報

-天気予報コム- -FC2-
リンク
ブロとも申請フォーム

この人とブロともになる

カテゴリー
最近の記事
ブログ内検索
最近のコメント
最近のトラックバック
RSSフィード
月別アーカイブ


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。