株式会社デジタル・フロンティア-Digital Frontier

Header

Main

  • TOP
  • DF TALK
  • Python と BAT を使って簡単なツールを作ろう!

Python と BAT を使って簡単なツールを作ろう!

2012/6/27

Tag: ,,,

こんにちは! 今年の3月よりDFのTDとして仲間入りした たつみ[@mtazmi]です。よろしくお願いします。
入社する前からDF_Talkはちょくちょく見ていたので、まさか自分が記事を投稿する側になるとは、と不思議な感じです。
ここに記事を書けるとやっとDFの一員になれた気がしますね。

最近では、10月に公開を控えた「バイオハザード ダムネーション」の
レンダリングのジョブ管理をしたり、トラブル対応に奔走する忙しい毎日を送っています。

僕は今まで独学でMelを使い始め、その後maya.cmdsでpythonを使い出したものの、
maya以外でのpythonの使い方をよく知りませんでした。

DFに来てから、レンダリング関連の作業などをする上で作ったツール制作を通して、
pythonとbatの組み合わせるだけで簡単にいろんなことが出来るということを知りました。

ということで、今回は自分の中でホットなこの python + bat でいろんなことをしてみるのをテーマにしてみます!

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

~お詫びと訂正~
batの構文に誤りがあり、正しく動作しない状態でした。

正しくは
誤:<スクリプトのまでのパス>hellowWorld.py
 ↓
正:<python.exeまでのパス> <スクリプトのまでのパス>hellowWorld.py
例:”C:\Program Files\python\python.exe” C:\hellowWorld.py

実際に試してみて、あれ?変だな?と思った方、大変申し訳ありませんでした。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

pythonのインストール

まずは、これが無いと始まりません
http://www.python.jp/Zope/download/pythoncore
python本体をインストールしましょう

簡単な実験から

以下のpythonスクリプトを作り、helloWorld.pyと保存します
■helloWorld.py

print 'hello world!'

次にbatファイルを作り、helloWorld.batと保存します
■helloWorld.bat

echo off
<python.exeまでのパス> <スクリプトのまでのパス>hellowWorld.py
pause

<~~のパス> という部分は、お使いの環境に合わせて指定して下さい

※1:スクリプトのパスは、バッチと同じ位置にあればファイル名だけでいけますが、
なるべくフルパスで指定してあげましょう

※2:もしパスの記述の中にスペースが入る場合(Program Filesなど)は、
ダブルクォーテーションで囲ってあげないとエラーになりますのでご注意!

出来たらバッチを叩いてみましょう!

hello World!と出ました
batからスクリプトを呼び出すのって結構簡単ですね!

引数を受け取ってみる

お次は引数です
batから引数をもらうには sys.argv を使います
■getArgv.py

import sys
for i in range(0, len(sys.argv)):
    print i, sys.argv[i]

batでpythonへ渡す引数はスクリプトのパスの後に書いてあげます
■getArgv.bat

echo off
<python.exeまでのパス> <スクリプトのまでのパス>getArgv.py test
pause

とします

バッチを叩くとこんな感じ

0 F:\tatsumim\_Docs\DF_Talk\getArgv.py
1 test

0番にはスクリプトのパスが、
1番には 「test」 という引数が入っているのが分かります

なのでもらった引数を使うには
sys.argv[1]以降を使えば良いようです

引数の実験その2

今度は、引数部分をこんな風に書きます
■getArgv2.bat

echo off
<python.exeまでのパス> <スクリプトのまでのパス>getArgv.py %1
pause

%1 はドロップされたファイル名やフォルダ名を渡してくれます

では、batに何かファイルをドラッグ&ドロップしてみます
先ほどのhelloWorld.pyでもドロップしてみます

ドラッグ&ドロップしたファイルのフルパスがプリントされました

フォルダではこんな感じです

これが出来るとちょっと夢が広がりませんか?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

では本格的な感じのを

引数として受け取ったフォルダ名を元に、中にあるma、mbデータを見つけたら階層を維持してバッチがある位置にコピーする、
というものを作ってみます。
これに似た機能のものは実際に制作現場で過去に作りました。
■copyMayaScenes.py

# -*- coding: utf-8 -*-

import os
import sys
import shutil

targetExt = ['ma', 'mb']

#==============================================================================
#==============================================================================
def runCopyFile(srcDir, dstDir):
    for sub in os.listdir(srcDir):
        newSrcPath = os.path.join(srcDir, sub)
        newDstPath = os.path.join(dstDir, sub)
        
        # これはディレクトリ?
        if os.path.isdir(newSrcPath):
            # ディレクトリだったらさらに掘り下げよう
            runCopyFile(newSrcPath, newDstPath)
        
        # ファイルだったら
        else:
            # 対象の拡張子か調べる
            if sub.split('.')[-1].lower() in targetExt:
                # フォルダが無ければ作っておく
                if not os.path.exists(dstDir):
                    os.makedirs(dstDir)
                
                # コピーする
                print '[Copy File]  :  ' + newDstPath
                shutil.copy2(newSrcPath, newDstPath)

#==============================================================================
def main():
    srcDir = sys.argv[1]
    dstDir = sys.argv[2]
    
    srcRoot = os.path.basename(srcDir)
    dstRoot = os.path.join(dstDir, srcRoot)
    
    # 基点となるフォルダを作っておく
    if not os.path.exists(dstRoot):
        os.makedirs(dstRoot)
    
    runCopyFile(srcDir, dstRoot)

if __name__ == '__main__':
    main()

#==============================================================================

お次はバッチ
■copyMayaScenes.bat

echo off
<python.exeまでのパス> <スクリプトのまでのパス>copyMayaScenes.py %1 %~dp0
pause

※ %~dp0 とはバッチが実行された場所を取得します

出来たらコピー先のフォルダへこのふたつをコピーして、
コピーしたいフォルダをバッチに投げ込んでください


こんな感じに色々データは入っているフォルダがあったとして…

↓ そのフォルダをドラッグ&ドロップすると


ma、mbデータのみがコピーされていますね
この画像では1階層しかありませんが、深いところにあっても階層構造を維持してコピーしてくれます

この処理に、oldフォルダは無視する、2回目以降の上書きチェックなどを付け加えていくと、より便利になっていきます

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

mayaを呼び出してみましょう


あああ ノード名が DF_Talk じゃなくて DF_Toke になってるよ!!
どうしよう、もうこの名前でたくさんシーン作っちゃってるし誰か助けてー
というのをどうにかする処理です

maya内で実行させるスクリプト
これはmayaが認識するスクリプトパスに入れておきます
本当はpymelを使いたいんですが、モジュールのインポート時間が結構かかるのであえてcmdsにしています
■DF_TokeToTalkCMD.py

import maya.cmds as cmds
import maya.mel as mel

def rename():
    DF_Toke = cmds.ls('DF_Toke')
    if DF_Toke:
        for toke in DF_Toke:
            cmds.rename(toke, 'DF_Talk')
            cmds.file(save=True)
    else:
        pass

    mel.eval('scriptJob -cf "busy" "quit -f -ec 0";')

maya内で DF_Toke という名前を見つけてリネームしてシーンを保存、mayaを閉じるという処理です
異なる階層に複数いる場合もあるので、for文で全てリネーム処理していきます

こちらはこれまでのようなバッチから呼び出すスクリプト
■DF_TokeToTalk.py

import os
import sys

mayaScene = sys.argv[1]
mayaExe = <maya.exeのパス>
mayaExe = '\"' + mayaExe + '\"'

mayaCmd = 'python(\\"import DF_TokeToTalkCMD;DF_TokeToTalkCMD.rename()\\")'
mayaCmd = '\"' + mayaCmd + '\"'


CMD = '\"' + mayaExe + ' -file ' + mayaScene + ' -command ' + mayaCmd + '\"'

os.system(CMD)

最後にバッチ
■DF_TokeToTalk.bat

echo off
<python.exeまでのパス> <スクリプトのまでのパス>DF_TokeToTalk.py %1
pause

バッチにシーンデータを投げ込むと、mayaが開き、処理が走ります

処理後のシーンを開くとこんな感じ

ノード名が直っていますね

今回はmaya.exeを使いましたが、mayabatch.exeを利用するとGUIを開く時間が無いのでより短い処理時間になります

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

いかがだったでしょうか?

仕事以外にも、写真の整理などちょっとしたツール制作なら出来そうですよね。
みなさんも楽しいpythonライフをお送り下さい!



Pocket

コメント

[…] ここからは以前たつみさんが書かれた内容と被る箇所がありますが大目に見てくれると嬉しいですヽ(°▽、°)ノエヘヘヘヘ […]

1 thought on “Python と BAT を使って簡単なツールを作ろう!”

コメントフォーム

コメントは承認制ですので、即時に反映されません。ご了承ください。

*