treedown’s Report

システム管理者に巻き起こる様々な事象を読者の貴方へ報告するブログです。会社でも家庭でも"システム"に携わるすべての方の共感を目指しています。

※https化しました。その影響でしばらくリンク切れなどがあるかもしれませんが徐々に修正していきます。 リンク切れなどのお気づきの点がございましたらコメントなどでご指摘いただけますと助かります。

バッチファイル内でバッチファイルを実行する時

バッチファイル内で別のバッチファイルを呼び出すとき、そのまま実行すると想定と違う動きをしてしまいます。
それを忘れていたのが今回のバッチファイルでした。

バッチファイル内でバッチファイルを実行するとき

別の作業でファイルをコピーしてEXE実行するバッチファイル(CpExec.bat)を使っていたのですが、別の用件そのバッチファイルを使い回して、「ファイルをコピーして実行した後に、そのバッチをタスクスケジューラに登録して常時実行にする」という作業が必要になりました。

単純に、以下のようなバッチファイル(CpExTask.bat)を作成して実行することにしました。
--------------------------------------------------------------
 ファイル名:CpExTask.bat
--------------------------------------------------------------
@echo off
rem 共有フォルダのバッチファイル実行
echo ファイルのコピーと実行をしています...
\\fserver\Share\CpExec.bat
echo ファイルのコピーと実行を完了しました。

echo タスクスケジューラへの登録を実行中...
ECHO .
SCHTASKS /Create /RU "%USERNAME%" /TN テスト用コピーバッチ実行 /TR "C:\Users\%USERNAME%\Downloads\Works\CpExec.bat" /SC ONLOGON /IT
echo タスクスケジューラへの登録内容を確認します。
taskschd.msc
pause
:end
--------------------------------------------------------------
ちなみに「CpExec.bat」はざっくりと
--------------------------------------------------------------
@echo off
SET COPYCMD=/Y
xcopy \\fserver\Share-1\○○.exe C:\Users\%USERNAME%\Downloads\Works
xcopy \\fserver\Share-1\○○.inf C:\Users\%USERNAME%\Downloads\Works
SET COPYCMD=

C:\Users\%USERNAME%\Downloads\Works\○○.exe
--------------------------------------------------------------
とこういう感じで、共有フォルダ上の.exeと.infをPC上のローカルフォルダにコピーして、ローカルの.exeを実行するという処理をしています。

両方のバッチファイルはともに実際には変数を使ったり、少々の判定を入れて条件分岐しているところがあるのですが、概ねやっていることは、

1) ファイルをコピーしてEXE実行するバッチファイル(CpExec.bat)を実行する
2) ローカルコピーしたバッチファイルCpExec.batをタスクスケジューラに登録する

という単純なステップです。

どんな動作をするか

CpExTask.batを実行すると(ちなみに画像はテスト環境で.exeの代わりにテスト用ファイル(ファイル名:test.txt)で動作確認したときの画像です。実際の環境で使う.exeは使っていません。)


コピーしてファイル実行(このテストではtest.txtをメモ帳で開く)までは実行してくれているのですが、どうもそれだけを実行したら処理が終わってしまうようで、プロンプトが返ってきて(画面中「c:\temp」のところ)います。

後に用意したタスクスケジューラ登録の処理がゴッソリ実行されていない状況、最初は気づかなかったのですが、気づいてからこれはなんだろうと疑問に思いました。

結論:CALLコマンド

昔、同じようなところで詰まっていたのを思い出しました。バッチファイルからバッチファイルを呼び出すときは、そのままファイルを記述すると上手くいかず、CALLコマンドを使ってバッチを起動する必要がある、ということを忘れていました。

バッチファイル-Aからバッチファイル-Bを呼び出したい場合には、CALLコマンドを使ってバッチファイルを呼び出す必要があります。書式は、

CALL バッチファイル-B.BAT

と記述します。

前述のバッチファイルCpExTask.batだと、

\\fserver\Share\CpExec.bat

の部分を、

call \\fserver\Share\CpExec.bat

と書き換えることで、CpExec.bat以降の行も正常に実行されました。

※書き換えてから再度実行してみた図。


※CALLコマンド経由でバッチを呼び出したので、コピーバッチの処理が完了した後、後ろの行にあるタスクスケジューラ登録の処理が動作しています。


タスクスケジューラ登録の処理が正常に完了したので、SCHTASKS コマンドにてバッチファイル後半で実行していたタスクも登録されていました。

CALLコマンドの解説

もうちょっと詳しくCALLコマンドについて記述しておきます。

バッチファイル-Aからバッチファイル-Bを呼び出した場合に、CALLコマンドでバッチファイルを呼び出していないと、バッチファイルBの処理を完了した時点で処理が完了してしまいます。

バッチファイル-Aの処理を最後まで完了させるには、バッチファイル-Bの処理が完了したあと、バッチファイル-Aに処理を戻してやらないといけない、この「終わったらバッチファイル-Aに戻ってきてね」という指示がCALLコマンドになります。

バッチファイルで別のバッチファイルを呼び出すならCALLコマンド、呼び出されたバッチファイルが完了したあとに、呼び出し元のバッチファイルに処理が戻ってきます。