私は Windowsの操作をかなり コマンドライン(CMD.EXE)で行う人なので、いまだに DOS時代のバッチファイルを結構使っています。
なお拡張子は .cmd 派です。
使う理由は、ほとんど以下の2つです。
一つは wrapper。
環境変数整えたりしてからコマンドを実行したいときに便利です。
もう一つは何度も実行するコマンドのショートカット。
何度も打つと疲れるしね。doskeyのmacroだとちょっと物足りないときにも。
しかし、いろいろやっていると困った事態に遭遇することもあります。
↓こいつを止めたいとか。
というわけで、今回は2つほど、私の知っている範囲でテクニック(?)の記録を残しておきたいと思います。
似たような記事は、たくさんありそうなので、個人的にマイナーだと思う物をピックアップしてみました。
バッチファイルの置いてあるディレクトリを、バッチから取得
「そんなの知ってる %~dp0
でしょ?」という方もいると思うのですが、実はこれで取れないケースがあります。
気持ちの悪いファイル名ですが、オペレータの方に朝実行してほしいバッチファイルがあるとして
"月曜 朝実行.cmd"
とかファイルを作って、これをパスの通った場所に置いておきます。
オペレータが朝 "月曜 朝実行" とかコマンドを叩くと、その中で %~dp0
はカレントディレクトリを返します。
バグじゃないの?って気がします。自動化しようね?って気もします。
そんなことは気にせず、ワークアラウンドです。
@ECHO OFF
GOTO :MAIN
:GET_BATCH_PATH
SET BATCH_PATH=%~dp0
EXIT /B 0
:MAIN
SETLOCAL
CALL :GET_BATCH_PATH
ECHO dp0 は %~dp0
ECHO 本当は %BATCH_PATH%
ENDLOCAL
環境変数でやり取りをするので、SETLOCAL/ENDLOCALで括っていますが、CALLで呼び出すと、ちゃんとバッチのパスを返してくれます。
やはりバグでは…と思いますが、気にするのはやめましょう。
私が知っている発生条件はこれだけなのですが、ほかにもあるかもしれません。バッチの格納されているパスをとるときの堅いやり方としてどうぞ。
バッチジョブを終了しますか?と言わせない
私の用途だと結構多いのですが、いろいろコマンドラインが長いので、それをラップするコマンドを作った場合です。
この場合、本当のコマンドを起動してバッチとしては終了となるのですが、こんな書き方になると思います。
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS
SET PYTHON_OPT=%1
python %PYTHON_OPT% -c "print('Hello, World!'); import time; time.sleep(5)"
ENDLOCAL
これをCTRL+Cで止めると、バッチは役目を終えているにも関わらずバッチ止めますか?って聞いてくるんですよね…。どっち選んでも意味ないし。
こうい場合、効くのが最後の行でGOTOのエラーを捕捉させる方法です。
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS
SET PYTHON_OPT=%1
GOTO #### 2>NUL || python %PYTHON_OPT% -c "print('Hello, World!'); import time; time.sleep(5)"
最初にGOTOの飛び先ラベルが見つからずエラー終了しますが、||
があるので、続くコマンドの実行に移ります。エラーを起こしたのがGOTOの場合、CMD.EXEは バッチのセッションが終了したかのように動作を続けます。
バグじゃないの?って思うかもしれません1。それほど気にしなくても良いのではと思います。
バッチジョブを終了しますか?と言わせない。その2
実は前のやり方でバッチジョブを終わらせた場合、一つ問題があって ウィンドウのタイトルが変になります。
これを回避したい場合 Windowのタイトルを明示的に つけ直すしかありません。
これは完全にバグですね。好きに付け直しましょう。
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS
SET PYTHON_OPT=%1
GOTO #### 2>NUL || TITLE cmd & python %PYTHON_OPT% -c "print('Hello, World!'); import time; time.sleep(5)"
これでバッチファイルを使ったラッパーを書いたときに、気になるCTRL+Cのメッセージを抑制できますね。
なんとなくバグ利用っぽいのが気になるところですが…。
おわり
FORを使った呪文等はわりと解説サイトが多いのですが、今回書いたあたりは、あまり解説されているサイトを見かけません。そんなこともあり共有させていただきました。
というわけで、皆様も良いバッチライフを。
-
一応、これ GOTOで失敗した場合は fallthroughして次の行を実行するのではなく、バッチセッションを終了させるという仕様なんだと思います(安全のため)。ただ、ここに
||
が出てくる事で +1 でコマンド実行できると。 ↩