対象OS:Windows 7/Windows 8/Windows 8.1/Windows Server 2008 R2/Windows Server 2012/Windows Server 2012 R2
「バッチ」(バッチコマンドともいう)とは、複数のコマンド列をあらかじめ「バッチファイル」と呼ばれるテキストファイルに記述しておいて、それらを順番に、自動的に実行させる機能のことである。ファイルのコピーやバックアップ、システムの設定変更、ツールの起動など、コマンドプロンプト上でいつも決まった処理をすることが多い場合、それらの処理をバッチファイル化しておけば、すぐに実行できるようになる。またタスクに登録することにより、毎日とか毎週など、ある決まった時間に起動して処理することも可能になる。
Windows OSで自動実行できるスクリプトとしては、バッチ以外にもWSHやPowerShellなども利用できる。だが、バッチは非常に古くから提供されているため(Windowsの前身のMS-DOS時代から利用できる機能である)、どのWindows上でも(ほとんど同じように)利用できるという利点がある。基本的には、単にコマンド列を列挙しておくぐらいの機能しか持っていないため、バッチファイルを作成するのはそう難しいものではない。
とはいえ、歴史的な経緯からバッチファイルには固有の(クセがあるといってもいい)機能や制限などがいくつかあるので、本TIPSでは基本的なバッチファイルの作成/利用方法についてまとめておく。対象はWindows 7/Windows Server 2008 R2以降とする。とはいえバッチの仕様はWindows NTからWindows 2000になる時にいくらか機能が強化されたぐらいで、それ以降はあまり大きな変化はない。
Windows OSのバッチファイルは単なるテキストファイルである。なのでメモ帳などを使って実行したいコマンド列を列挙し、文字コードを「ANSI」あるいは「Shift-JIS」形式にして保存する(UnicodeやUTF-8にしてはいけない)。ファイルの拡張子は「.BAT」か「.CMD」のいずれかにしておく(どちらでも特に違いはないが、今なら.CMDの方がよいだろう)。
バッチファイルの各行には、実行したいコマンドを(基本的には)1行ずつ記述する。例えば、コマンドプロンプトの文字コード(表示モード)を切り替える「chcp.exe」というコマンドがあるが、これをバッチファイルで使う場合は次のようにする(chcpについては関連記事参照)。us.cmdとjp.cmdという2つのコマンドの例である。
C:\Command>type us.cmd ……コンソール(コマンドプロンプトの表示)を英語モードに切り替えるバッチファイル
@echo off
setlocal
rem Change the active CODE PAGE to 437 (United States)
chcp 437
C:\Command>type jp.cmd ……日本語モードに戻すバッチファイル
@echo off
setlocal
rem Change the active CODE PAGE to 932 (Japan)
chcp 932
C:\Command>
それぞれ、先頭に「@echo off」という記述があるが、これは実行中のコマンド列を画面に表示させないようにするための定型文である。こうしておかないと、いちいちコマンド列が表示されて煩わしくなる。ただし、バッチファイルのコーディング中やテスト中はこの文は入れずに、何が実行されるのかを確認した方がいいだろう。バッチファイルが完成したら、最後にこの行を追加しておく。
ちなみに「@echo off」ではなく単に「echo off」だと、この行そのものは表示され、次の行から非表示になる。さらにバッチでは行頭に「@」があると、その行だけは非表示になるが、いちいちすべての行頭に「@」を付けるのは現実的ではないので、通常は先頭で「@echo off」とする。
2行目にある「setlocal」は、環境変数に対する操作をローカル化するコマンドである。詳細は省略するが、@echo offと共に、決まり文句のようなものだと思っておけばよいだろう。setlocalがあると、このバッチファイル中で環境変数を作成したり、値を変更したりしても、その結果は外部へ伝わらない。
3行目には、いずれも「rem 〜」文があるが、これはコメントを表すコマンドであり、実行されることはない。バッチファイルの説明などを記述しておこう。
4行目にある「chcp 〜」が実際に実行されるコマンドである。まずコマンドプロンプトに手動で入力して実行し、そのコマンドが正しく起動できるかどうか確認してから、コマンド列をバッチファイルに貼り付けるとよいだろう。コマンドのヒストリーの確認方法などについては関連記事を参照していただきたい。
バッチファイルを実行するには、コマンドプロンプトや[ファイル名を指定して実行]ダイアログでバッチファイルのパス名を指定すればよい。だがいちいちフルパスで指定しなければならないのでは、とても面倒である。コマンドプロンプトの場合は、カレントフォルダー中にそのバッチファイルが存在すれば、フォルダー名の部分は指定しなくてもよいものの、最初にバッチファイルのあるフォルダーにcdコマンドで移動するのも、また面倒である。
バッチファイルをよく使うなら、どこか一カ所にバッチファイルをまとめて保存しておき、そのフォルダー名をPATH環境変数に登録しておくのがよい。例えば筆者は「C:\Command」というフォルダーを作成して、この中によく使うコマンドや自作のバッチファイル、(WSHやPowerShellの)スクリプトなどを保存している。そしてPATH環境変数の最後に「;C:\Command」を追加している。
PATH環境変数の設定方法については関連記事を参照していただきたい。環境変数には「ユーザー環境変数」と「システム環境変数」の2種類があるので、用途に応じていずれかのPATH環境変数の末尾に、バッチファイルを保存してあるフォルダー名を追加する(末尾ではなく前の方に追加すると、同じ名前のコマンドがあった場合に優先して実行される)。独立したフォルダーを用意せず、システムのデフォルトPATHに含まれる「C:\Windows」などにバッチファイルを保存すると、後でバッチファイルの更新などが面倒になるので、止めた方がいい。
バッチファイルでは通常、CUIのコマンドを起動することが多いだろう。しかしGUIを使うWindowsのアプリケーションプログラムを起動することもできる。例えば、以下は「WZ Editor 8(WZ Software)」という(筆者がいつも使っている)テキストエディターを起動するバッチの例である。
※「wz8.cmd」というバッチファイルの内容例(1行のみ)
"C:\Program Files (x86)\WZ EDITOR 8\wzeditor.exe" %*
ユーザーがインストールしたWindowsのアプリケーションは、通常は「C:\Program Files」や「C:\Program Files (x86)」などの下にインストールされていて、起動するには[スタート]メニューからGUI操作で目的のメニュー名を探さないと起動できないことが多い。
そこで、こうやってバッチファイルを用意しておくと、普段からコマンドプロンプトを使っている場合は、単に「wz8」というコマンド名を入力するだけですぐに起動できて便利である。Office Wordをよく使うなら、「C:\Program Files (x86)\Microsoft Office\Office15\WINWORD.EXE」を起動するようなword.cmdを作っておけばよいだろう。
任意のプログラムを起動するには、このように行の先頭に実行ファイルのフルパス名を記述し(空白文字が含まれる場合は、上の例のように引用符で囲むこと)、さらに「%*」という表記を追加しておく。
「%*」は、バッチファイルに渡された引数全体を表す記号である。例えば「wz8 a.txt b.txt c.txt」として起動すると、3つのファイル名を引数として、テキストエディターが起動されることになる(引数の表記方法については「help call」コマンドのヘルプを参照のこと)。
バッチファイルへの引数を1つずつ参照したい場合は、「%1」「%2」……「%9」とすればよい。ただし、この指定方法では最大で9つまでしか参照できない。10個目以降の引数を参照したい場合は「Shift」というコマンドを併用する。Shiftコマンドを実行すると、最初の引数(%1)が削除され(シフトアウトされ)、2つ目以降の引数が「%1」「%2」……「%9」で参照できるようになる。後述するgotoなどの制御構造と組み合わせれば、全ての引数を、例えば「%1」だけで順に参照できるようになる。詳細は「help shift」コマンドのヘルプを参照のこと。
バッチファイルへの引数はそのまま使うだけでなく、例えばパス名ならそれを分解して、パス部分、基本ファイル名部分、拡張子部分などに分解することもできる。詳細はやはり「help call」を参照していただきたい。
バッチファイルとして作成したコマンドは、コマンドプロンプトから起動するだけでなく、「ファイル名を指定して実行」でも起動できるようになる。例えば[Windows]+[R]キーで「ファイル名を指定して実行」ダイアログを表示させ、「wz8」と入力すると、先ほど作成したバッチファイルからWZエディターが起動される。
ただしこの場合、目的のアプリケーションのウィンドウだけでなく、実行中のバッチファイルのウィンドウ(実際にはコマンドプロンプトのウィンドウ)も表示される。このウィンドウはアプリケーションを終了するまで表示されたままになっており、これでは見栄えが悪いし、余計なウィンドウが表示されることによって、操作ミスを起こす可能性もある。バッチファイルの先頭に「@echo off」を入れても、コマンドプロンプトのウィンドウは表示される(echo offのために、画面は真っ黒のままだが)。
このような状況を避け、コマンドプロンプトのウィンドウを出さずに目的のアプリケーションを起動するには「start "" <パス名> %*」というコマンドにすればよい。startはコマンドプロンプトの内部コマンドで、指定された項目を起動するためのものである。startコマンドはデフォルトでは、起動したプログラムの実行終了を待たないので、バッチファイルはすぐに終了し、黒いコマンドプロンプトのウィンドウを見ることはなくなるだろう。
※「wz8.cmd」というバッチファイルの内容例(更新版)
start "" "C:\Program Files (x86)\WZ EDITOR 8\wzeditor.exe" %*
startコマンドは、実行ファイルだけでなく、さまざまな特殊フォルダーを開けるなど高機能である。startコマンドの第1引数にある「""」はアプリケーションのタイトルを設定する文字列だが、不要なので、このように空文字列にしておけばよい。startコマンドについては関連記事のTIPSや「help start」のヘルプを参照のこと。
バッチに対する引数を参照できるのは、「%1」や「%*」だけではない。それ以外にも環境変数やバッチ用のローカル変数などもいくらか定義されており、それらを参照したり、(単純ながら)文字列演算や数値演算させたりする機能も用意されている。
環境変数やローカルの変数は「%TMP%」のように、変数名を「%」で囲むと参照できる。あらかじめ定義されている代表的な変数については、関連記事や「help set」コマンドの説明を参照していただきたい。
あらかじめ定義されている「%DATE%」や「%TIME%」などに対して文字列演算や数値演算などを使うと、現在の日付や時刻、コンピューター名、ドメイン名などをベースにしたファイル名を合成できる。これを使って、例えば自動的に日付別にファイルをバックアップする、ログファイルを整理させるといったコマンドを作ることが可能だ。関連記事の例などを参考にしていただきたい。
バッチファイル中では、ifやgoto、callなど、いくつかの制御構文が利用できる。
if文を使うと、ある条件に一致した場合にコマンドを実行したり、制御を移行させたりできる。
if文にはいくつか書式があり、主要なものは次の通りである(詳細は「help if」参照)。
一番下の例では、両方の文字列が数字だけなら数値として大小比較が行われ、そうでなければ文字列として比較される。利用可能な <演算子> としては、「EQU(等しい)」「NEQ(等しくない)」「LSS(より小さい)」「LEQ(以下)」「GTR(より大きい)」「GEQ(以上)」の6種類がある。
下の2つは文字列として比較するためのものだ。これらは特に、片方が空文字列の場合に注意が必要である。例えば引数が1つ以上あるかどうか判定するために「if %1=="" echo error」としても、%1が空文字列だと「if =="" echo error」と解釈され、これは構文エラーとなる。文字列を比較したい場合は、空文字列でも問題ないように、両方に何かのダミー文字列を付けたり、引用符で囲んだりすること。例えば「if "%1"=="" echo error」や「if /%1==/ echo error」のようにする(バッチファイルでは、文字列を引用符で囲む必然性はない)。
※引数があるかどうかをチェックするバッチの例
C:\Test>type samplebatch.cmd
@echo off
setlocal
if xx%1==xx goto usage ……引数が空かどうかチェック。なければエラーにする。先頭に「xx」を付けて、空にならないようにしている
echo 引数は「%*」です。 ……引数があれば、それをまとめて出力する
goto :eof ……終了させる(gotoについては後述)
:usage ……引数がない場合は、ヘルプメッセージを表示する
echo 使い方 -- %0 : 1つ以上の引数を付けて起動してください。
C:\Test>samplebatch ……引数なしで起動してみる
使い方 -- samplebatch : 1つ以上の引数を付けて起動してください。
C:\Test>samplebatch a b c ……引数ありで起動してみる
引数は「a b c」です。
C:\Test>
指定されたファイルやフォルダーが存在するかどうかは「if exist <パス名>」でチェックできる。ただしファイルかフォルダーかの区別は基本的にはできないことになっている。末尾に「\」を付けると(例「if exist %1\ echo %1はフォルダーです」)、フォルダーなら真になり、ファイルなら偽になることが多い。しかし、シンボリックリンクやアクセス権の関係などで、常にこの方法が正しいとは限らないようだ。利用する場合は、事前に十分テストしたり、フォルダー中にダミーファイルなどを作成させてみて、成功するかどうかなどで判断したりするのがよいだろう。
※複数のバージョンのWZエディターがインストールされている場合に、そのいずれかを起動する「wz.cmd」というバッチファイルの例
C:\Command>type wz.cmd
@echo off
setlocal
if not exist "C:\Program Files (x86)\WZ EDITOR 8\wzeditor.exe" goto :next1
start "wz8" "C:\Program Files (x86)\WZ EDITOR 8\wzeditor.exe" %*
goto :eof
:next1
if not exist "C:\Program Files (x86)\WZ EDITOR 7\wzeditor.exe" goto :next2
start "wz7" "C:\Program Files (x86)\WZ EDITOR 7\wzeditor.exe" %*
goto :eof
:next2
if not exist "C:\Program Files\WZ EDITOR\wzeditor.exe" goto :next3
start "wz4" "C:\Program Files\WZ EDITOR\wzeditor.exe" %*
goto :eof
:next3
echo no WZ editor.
C:\Command>
if文が長くなる場合は ( 〜 ) を使って複数行のブロックにしたり、elseブロックを使って複雑な条件を記述したりできる。
C:\Test>type samplebatch2.cmd ……先の例をif else ブロックで書き換えた例
@echo off
setlocal
if not xx%1==xx ( …… ( で囲んで複数行をまとめてブロックにできる
echo 引数は「%*」です。 ……条件成立時に実行されるブロック
) else ( ……elseブロック
echo 使い方 -- %0 : 1つ以上の引数を付けて起動してください。
)
C:\Test>samplebatch2
使い方 -- samplebatch2 : 1つ以上の引数を付けて起動してください。
C:\Test>samplebatch2 123 456
引数は「123 456」です。
C:\Test>
「goto <ラベル>」は指定したラベルへジャンプするコマンドで、ラベルは行頭の「:」(コロン)に続けて「ラベル名」を指定することで定義する(ラベルを定義している行には他のコマンドは記述せず、ラベル単独にすること)。また暗黙のラベルとして、バッチファイルの最後には「:eof」というラベルがあるものと想定されており(EOFはファイル終了、End Of Fileの略)、「goto :eof」とするとバッチファイルが終了する(「goto eof」ではなく「goto :eof」にしないとエラーになる。「help goto」参照)。
C:\Test>type gototest.cmd ……goto文とラベル定義のテスト
@echo off
setlocal
goto label2 ……いきなり2番目のブロックへジャンプしてみる
:label1 ……ラベルの例
echo 1番目のechoコマンド
goto :eof ……終了させる
:label2
echo 2番目のechoコマンド
goto label3 ……3番目のecho文へジャンプする
:label3
echo 3番目のechoコマンド
goto label1 ……先頭のecho文へジャンプする
C:\Test>gototest ……実行させてみる
2番目のechoコマンド ……正しく2番目→3番目→1番目の順に実行されている
3番目のechoコマンド
1番目のechoコマンド
C:\Test>
バッチファイルは最後まで到達すると自動的に終了する。それ以外にも、上のように「goto :eof」で終了させてもよいし、他にも「exit 」コマンドで終了させてもよい。exitの場合は、例えば「exit /b 1」のようにして「終了コード」を返させることもできる。終了コードは、通常はエラーなしだと0、エラーがある場合は何らかの状態を表す1以上のコードを返すのが普通である(詳細は「help exit」参照。/bを付けないと、呼び出したコマンドプロンプトも終了してしまうので注意)。受け取ったエラーコードは、呼び出した側で「if errorlevel <コード> 〜」や「%errorlevel%」変数でを使ってチェックできる。
バッチファイル中で他のバッチファイルを呼び出すと、信じがたいかもしれないが、デフォルトでは別のバッチファイルへ制御が移った後、そのまま戻ってこない(これも大昔のシステムとの互換性のため)。呼び出した先のバッチファイルが終了すると、最初に呼び出したバッチファイルもそのまま終了したしたことになってしまう。
まず、直接呼び出す場合の例である。
C:\Test>type calltest-bad.cmd ……意図しないバッチ呼び出しの例
@echo off
setlocal
echo バッチ呼び出し前
gototest ……外部のバッチファイルを呼び出してみる
echo バッチ呼び出し後
C:\Test>calltest-bad
バッチ呼び出し前 ……起動したバッチファイル
2番目のechoコマンド ……外部のバッチファイル
3番目のechoコマンド
1番目のechoコマンド
……「echo バッチ呼び出し後」が実行されていない
C:\Test>
次は、call文を使ってバッチファイルを呼び出す例である。
C:\Test>type calltest-ok.cmd ……正しいバッチ呼び出しの例
@echo off
setlocal
echo バッチ呼び出し前
call gototest
echo バッチ呼び出し後
C:\Test>calltest-ok
バッチ呼び出し前
2番目のechoコマンド ……呼び出し先
3番目のechoコマンド
1番目のechoコマンド
バッチ呼び出し後 ……「echo バッチ呼び出し後」が正しく実行されている
C:\Test>
独立した外部のバッチファイルではなく、同じファイル内にcallで呼び出せるブロックを定義することもできる。関連する処理を1つのファイル内でまとめて管理できるので便利である。詳細は「help call」を参照のこと。
C:\Test>type kaeru.cmd ……バッチの内容の確認
@echo off
setlocal
call :pyokopyoko かえる ……ローカルのバッチの呼び出し×4回。ラベル名に続けて、引数を列挙できる
call :pyokopyoko み
call :pyokopyoko あわせて
call :pyokopyoko む
goto :eof ……バッチの終了
:pyokopyoko ……ローカルのバッチのラベル
call :pyoko %1 ぴょこ ……2つの引数を付けて、さらにローカルのバッチを呼び出してみる
exit /b ……バッチからのリターン
:pyoko
echo %*ぴょこ
……最後まで来ると自動的に呼び出しからリターンするが、今後、この後ろにさらに何か追加するかもしれないので、忘れないように、あらかじめめ「exit /b」を入れておく方がよい
C:\Test>kaeru.cmd ……バッチ呼び出し
かえる ぴょこぴょこ ……結果
み ぴょこぴょこ
あわせて ぴょこぴょこ
む ぴょこぴょこ
C:\Test>
コマンドプロンプトのfor文はさまざまな機能を持つ。指定した引数のリストを使って処理を繰り返したり、ファイルやフォルダーの一覧を取得して処理したり、指定されたステップで数値を変更させながら(例:変数Iを1から100まで1ずつ増やしながら)繰り返したりできる。非常に機能が多いので、これについては今後別記事で紹介する。基本的な使い方については「help for」コマンドを参照していただきたい。
なお1つだけ補足しておくと、コマンドラインで使う場合とバッチファイル中で使う場合では、for文の制御変数の記述方法が異なるので注意が必要である。例えば、コマンドラインでは「for %i in (*.*) do echo %i」とすればファイル名の一覧が表示される。しかしこれをバッチファイル中へ組み込む場合は「%」を重複させて、「for %%i in (*.*) do echo %%i」のようにしなければならない。
コマンドプロンプト上で利用するツールには、ユーザーによるインタラクティブな入力や操作が必要なものがある。そのようなコマンドであっても、例えば自動応答ファイルなどを作成して与えれば、バッチファイル中でも利用できることがある。
例えばファイルなどのアクセス権を設定する「cacls.exe」というコマンドがある(これは現在ではすでに非推奨のコマンドとなっており、後継のicacls.exeなどの使用が推奨されている)。このコマンドでアクセス権を変更しようとすると、途中で「Y」というキーを入力しないと先へ進まないようになっている。だが次のTIPSで紹介しているように、「echo Y」コマンドで「Y」という文字を生成させ、それをパイプでcaclsコマンドに与えるとユーザーの介入なしに処理が完了する。
コマンドによってはスクリプトファイルを受け付けるものもある(例:ftpやdiskpart、netshコマンドなど)。これらを使う場合、スクリプト中に環境依存の項目、例えばドライブ名や一時フォルダー、プロファイルフォルダーの場所、日付や時刻、コンピューター名、絶対パスなどを埋め込んでおかないと処理できないことがある。例えばdiskpartコマンドで仮想ディスクファイルを作成する場合、場所を絶対パスで指定しないといけない(TIPS「仮想ディスクをコマンドラインから作成・管理する」参照)。
このような場合は、バッチファイル中でechoコマンドと環境変数、ファイルへのリダイレクトなどを組み合わせて動的にスクリプト用のテキストファイルを作成し、それをコマンドにスクリプトとして与える、という方法を使うとよいだろう。
本TIPSでは、バッチファイルの基本的な作り方について簡単にまとめてみた。より進んだ使い方や、バッチ以外のスクリプト(WSHやPowerShellなど)については、別TIPSで取り上げる。
■この記事と関連性の高い別の記事
Copyright© 1999-2015 Digital Advantage Corp. All Rights Reserved.
IT企業ラックの社員のお子さん「かよちゃん」が心臓移植の必要な難病と闘っています。皆さまの温かいご支援をお待ちしています。ぜひご協力を。