forLifeMap

仕事、投資、技術メモ、オカルト、その他クソミソな趣味や日常についてあれこれ綴る、日記帳というより雑記帳。忘却の彼方に置き忘れた夢と情熱を求めて彷徨中。

今更ながらDOSバッチ

仕事上、コマンドプロンプトで実行される
バッチファイルを作成する機会が多いので、
備忘録がてらメモしてみる。

f:id:hNeumann:20171124222205j:plain


なお、当エントリーでは、コマンドをすべて
大文字で記載しているが、別に小文字でも
問題ないので、その辺はお気になさらず。

1.冒頭のおまじない

@ECHO OFF	… 実行中のコマンド非表示
SETLOCAL … 環境変数の操作のローカル化

無論、SETLOCALと対を為すENDLOCALという
コマンドもあるが、バッチ終了時に暗黙的に
自動実行されるため、基本的に書かなくてもいい。

2.コメント

REM コメント	… 正しいコメント方法
:コメント … ラベルをコメントとして使用

 なお、複数行をコメントアウトしたい場合、
GOTO文とラベルを使って対象を「GOTO :○○」
「:○○」で囲えば無理矢理実現できる。

3.システム日付・時刻

日付の場合は一発でYYYYMMDD形式で取得できる。

%DATE:/=%	… 「/」を除去した日付

なお、曜日を取得しようと思うと
それなりに作りこみが必要。

時刻の場合、一発でhhmmss形式で
取得することができない。そのため、
変数Tに欲しい形式で加工する。

SET T=%TIME:~0,8%	… %TIME%の先頭8文字取得
SET T=%T::=% … 「:」を除去
SET T=%T: =0% … 半角スペースを0埋め

これでTにhhmmss形式でシステム時刻が
セットされる(ミリ秒は除外している)。

4.実行ファイル

コマンドプロンプトで「CALL /?」と叩けば
詳細を教えてくれる。

%0     … フルパスのファイル名(""あり)
%~0 … フルパスのファイル名(""なし)
%~f0 … フルパスのファイル名
%~d0 … ドライブ文字
%~p0 … ドライブ文字以降のパス
%~n0 … ファイル名
%~x0 … ファイル拡張子
%~s0 … フルパスのファイル名(短縮あり)
%~a0 … ファイルの属性
%~t0 … ファイルのタイムスタンプ
%~z0 … ファイルのサイズ

%~dp0 … ファイル格納先のフルパス
%~nx0 … 拡張子つきのファイル名
%~ftza0 … DIRコマンド風の出力

なお、
「C:\Users\Public\Desktop\CommandPrompt_TEST\echo.bat」
上記内容を記述して出力した結果は
下記の通りである。

%0     "C:\Users\Public\Desktop\CommandPrompt_TEST\echo.bat"
%~0 C:\Users\Public\Desktop\CommandPrompt_TEST\echo.bat
%~f0 C:\Users\Public\Desktop\CommandPrompt_TEST\echo.bat
%~d0 C:%~p0 \Users\Public\Desktop\CommandPrompt_TEST\
%~n0 echo
%~x0 .bat
%~s0 C:\Users\Public\Desktop\COMMAN~1\echo.bat
%~a0 --a--------
%~t0 2017/11/24 20:40
%~z0 189

%~dp0 C:\Users\Public\Desktop\CommandPrompt_TEST\
%~nx0 echo.bat
%~ftza0 --a-------- 2017/11/24 20:40 189 C:\Users\Public\Desktop\CommandPrompt_TEST\echo.bat

 

5.引数

変数%0が自分自身を表す変数であったのに対し、
%1、%2、%3、…というのは、バッチ実行時に
渡された引数の内容を表す変数である。

test.bat "hoge.txt" 1

としてtest.bat実行時に引数が渡された場合、

ECHO %1  … "hoge.txt"
ECHO %2  … 1

が格納されることになる。
ちなみに、引数は%1~%9までの最大9個まで
しか渡すことができず、それ以上の引数を
渡したい場合は作りこみが必要。

7.DOS窓からの入力

SET /P 変数名="入力を促すメッセージ"

DOS窓からの入力を受け取ることが出来る。
よくあるパターンとして、

SET /P I="処理を実行します。よろしいですか?(Y/N): "
IF "%I%"=="Y" (GOTO MAIN)
IF "%I%"=="y" (GOTO MAIN)
EXIT
:MAIN
(以降、メイン処理を記述)

のように、処理実行前の確認用として
用いられることが多い。

8.リダイレクト出力

>   ファイル名  … 標準出力(新規)
>> ファイル名 … 標準出力(追記)
2> ファイル名 標準エラー出力(新規)
2>> ファイル名 標準エラー出力(追記)
> NUL 2>&1 … NULL破棄

(おまけ)
ECHO. … 空行の出力

最後の空行出力は、リダイレクトと直接関係は
ないような気がするけど、まぁよく使う
コマンドなので、とりあえずここに記載。

9.デバッグ確認

処理の中で不具合が検出された場合、

ECHO %変数名%  … 変数のウォッチ
PAUSE          … 処理の一時停止(ブレーク)

を駆使すれば、変数の中身の変遷を
追いかけることが出来る。

 10.サブルーチン定義

バッチには関数が定義できない。そのため、
ラベルを用いてサブルーチンを定義する
手法がよく用いられる。以下、例を挙げる。

@ECHO OFF
SETLOCAL

CALL :SUB1 %~dp0
ECHO %ERRORLEVEL%

CALL :SUB2 "fuga.txt"
ECHO %ERRORLEVEL%

ECHO.
PAUSE
EXIT

:SUB1
IF "%~d1"=="C:" EXIT /B 0
IF "%~d1"=="D:" EXIT /B 1

:SUB2
IF EXIST %1 EXIT /B 0
IF NOT EXIST %1 EXIT /B 1

簡単に説明しておくと、まずSUB1をCALL
する際に引数%~dp0を渡している。
これは、バッチを実行しているファイルの
ドライブ文字で、SUB1でドライブ文字の
判定を行っている。ドライブが「C:」であれば
0を、「D:」であれば1をエラー用変数に返す。

その後、SUB2をCALLして引数"fuga.txt"を渡す。
SUB2では"fuga.txt"がバッチが格納されている
フォルダに存在するか判定しており、ファイルが
あれば0を、なければ1をエラー用変数に返す。
なお、実行結果はこうなった。

0  … ドライブは「C:」
1  … "fuga.txt"は存在しない

続行するには何かキーを押してください . . .

ラベルを用いた場合、メイン処理の末尾に
「EXIT」コマンドを入れておかないと、ラベルに
記述した処理がすべて実行されてしまう。
また、サブルーチンの終了時は「EXIT /B」に
しないとサブルーチンどころかバッチそのものが
終了してしまうため注意が必要である。

おわりに 

さて、思ったより長くなってしまった。
IFやFORの構文も書こうと思ったけど力尽きた。
どうせHELPコマンド叩けばすぐに分かるし…
まぁ、気が向いた時に更新しようと思う。

しかし、Windowsスクリプト言語と言えば
Powershellがもう少しメジャーに扱われても
いいような気がするが、現場レベルで言うと
やはりまだまだDOSバッチやVBscriptが幅を
利かせているのが現状ではなかろうか。

バッチ作成は普通にテキストエディタ使えば
問題なく作成できるが、VisualBatなる
IDEも存在するので、気になる方は
使用されてみては如何だろう。

では、これにて失礼。