Python と BAT を使って簡単なツールを作ろう!
2012/6/27
こんにちは! 今年の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
1 | print 'hello world!' |
次にbatファイルを作り、helloWorld.batと保存します
■helloWorld.bat
1 2 3 | echo off <python.exeまでのパス> <スクリプトのまでのパス>hellowWorld.py pause |
<~~のパス> という部分は、お使いの環境に合わせて指定して下さい
※1:スクリプトのパスは、バッチと同じ位置にあればファイル名だけでいけますが、
なるべくフルパスで指定してあげましょう
※2:もしパスの記述の中にスペースが入る場合(Program Filesなど)は、
ダブルクォーテーションで囲ってあげないとエラーになりますのでご注意!
hello World!と出ました
batからスクリプトを呼び出すのって結構簡単ですね!
引数を受け取ってみる
お次は引数です
batから引数をもらうには sys.argv を使います
■getArgv.py
1 2 3 | import sys for i in range ( 0 , len (sys.argv)): print i, sys.argv[i] |
batでpythonへ渡す引数はスクリプトのパスの後に書いてあげます
■getArgv.bat
1 2 3 | 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
1 2 3 | echo off <python.exeまでのパス> <スクリプトのまでのパス>getArgv.py %1 pause |
%1 はドロップされたファイル名やフォルダ名を渡してくれます
では、batに何かファイルをドラッグ&ドロップしてみます
先ほどのhelloWorld.pyでもドロップしてみます
ドラッグ&ドロップしたファイルのフルパスがプリントされました
フォルダではこんな感じです
これが出来るとちょっと夢が広がりませんか?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
では本格的な感じのを
引数として受け取ったフォルダ名を元に、中にあるma、mbデータを見つけたら階層を維持してバッチがある位置にコピーする、
というものを作ってみます。
これに似た機能のものは実際に制作現場で過去に作りました。
■copyMayaScenes.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | # -*- 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
1 2 3 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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
1 2 3 | echo off <python.exeまでのパス> <スクリプトのまでのパス>DF_TokeToTalk.py %1 pause |
バッチにシーンデータを投げ込むと、mayaが開き、処理が走ります
今回はmaya.exeを使いましたが、mayabatch.exeを利用するとGUIを開く時間が無いのでより短い処理時間になります
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
いかがだったでしょうか?
仕事以外にも、写真の整理などちょっとしたツール制作なら出来そうですよね。
みなさんも楽しいpythonライフをお送り下さい!
[…] ここからは以前たつみさんが書かれた内容と被る箇所がありますが大目に見てくれると嬉しいですヽ(°▽、°)ノエヘヘヘヘ […]
Posted at 2013.08.26 14:02 by デジタル・フロンティア-Digital Frontier | DF TALK | AfterEffectsスクリプトの使用状況をExcelに出力してみよう ~JavascriptとPythonの連携~