-
Notifications
You must be signed in to change notification settings - Fork 0
MS_BAT
-
TOP > インフラストラクチャ > シェル > スクリプティング(
MS_Scripting.md)- BAT
- VBScript(
MS_VBS.md) - PowerShell
- Python(Python on Windows:
MS_PythonOnWindows.md)
UNIX系OSのシェル・スクリプトに相当する。
以下のようなトピック情報を纏めています。
- batファイルの勘所
- debugの方法
- 環境変数 / 遅延展開
-
batファイルは、
- CMDで、手でコマンドを逐次実行する手順を、ほぼそのまま、batファイルに記述して、
- 実行で順次実行する
ためのファイルです。
-
batファイルはCMDの中で実行します。
- エクスプローラ上でダブルクリックすると、
- CMDが開いて、その中で実行、
- 終了すると、CMDが閉じます。
- ヘルプ
コマンドそれぞれの構文については記述しません。
コチラの様に/?をつけて実行するとヘルプが表示されます。 - サンプル
サンプルや例が必要であれば、以下の様に検索すると多数見つかります。
site:microsoft.com バッチファイル for
batファイルを呼び出すときに、引数を指定できます。
testbat.bat arg1 arg2
batファイル内では、引数は %数字 で取り出します。
echo arg1 は %1
echo arg2 は %2
batファイル内で、引数を変数に代入したり(set 変数名=値)、
変数を表示したり(変数の場合は %変数名% で囲む)、
変数の一部の文字を置き換えたり(%変数名:文字列1=文字列2%)できます。
set a1=%1
echo a1 は %a1%
echo 文字置き換え %a1:g=G%
%数字 は 1 から 9 まで使用できます。
もし batファイルの引数が 10個以上必要な場合は、shift を使って、引数を1つ前へずらします。
:_nextparam
echo %1
shift
if NOT "%~1" == "" goto :_nextparam
:_end
- 引数の数字に 0 を指定すると、batファイル名を取り出すことも出来ます。
- 例えば、batファイルのファイル名から拡張子違いのデータファイル名を生成するには、以下の様にします。
- batファイル名が
c:\temp\test1.batであれば、"c:\temp\test1.csv"が変数%dat%に代入されます。
set dat="%~dpn0.csv"
-
%0は batファイル自身を表し、 -
~は 次の文字に従って解釈することを指定、 -
dpnは ドライブ・フォルダパス・ファイル名 を取り出します。 - 最後に
.csvをくっつけます。
batファイルでは、%変数名% は、環境変数と共通です。
- Windowsの環境変数は、
- コンピュータ >> プロパティ >> 詳細設定 に設定があります。
- この内容は、batファイルから
%環境変数名%で参照できます。
- batファイル内での環境変数は、
- 下記でのみ、参照できます。
- batファイル内
- および、batファイルから呼び出すコマンド
-
set 環境変数名=値を記述しても、
コンピュータ >> プロパティ >> 詳細設定 の環境変数は変更されません。
- 下記でのみ、参照できます。
※ 恒久的に設定するには setx を使う(環境変数の設定方法を参照)。
また、setlocal / endlocal で囲むと、変更をその範囲に閉じ込められる。
引数、変数は、" " で囲んだまま展開されます。
以下の a1.bat ファイルがある場合、
set a=%1abc
a1 "ABC" と実行すると、以下の様に展開されて set が実行され、変数 a に代入されます。
set a="ABC"abc
「"」を処理するには、%~1 の様に「~」をつけて「"」を取り去ります。
set a=%~1abc → set a=ABCabc
set a="%~1abc" → set a="ABCabc"
余分な「"」を取り去りつつ、全体を「"」で囲むことができます。
「"」の扱いは、例えば if文 でどう記述するか、どう展開されるか、に影響します。
batファイルが以下の場合、
if %1 == ABC (
echo ok
)
a1 ABC と起動すると ok ですが、a1 "ABC" と起動すると ok になりません。
この場合、以下の様にすると、a1 "ABC" a1 ABC どちらでも ok になります。
if "%~1" == "ABC" (
echo ok
)
for文を使って、区切り文字(delims=)、カラム(tokens=)を指定して読み取ります。
下の batファイルは、csv の 2つめ・3つめ を echo します。
また batファイルの引数に指定した値を 1カラム目に持つ行の 4カラム目を表示します。
for文の ( ) 内は、' ' で囲んで、コマンドの出力から得ることを指定しています。
@setlocal
@echo off
set csv="%~dpn0.csv"
for /F "tokens=1,2,3,4 delims=," %%a in ('cmd.exe /c type %csv%') do (
echo %%b %%c
if "%%a" == "%~1" (
echo 引数で指定されたパラメタは %%d です
)
)
@endlocal
bbb ccc
33 44
234 456
引数で指定されたパラメタは 678 です
for文に指定した %%a と tokens= に指定した数に従って、
%%a %%b %%c … の順に自動で変数名が使われます。
batファイルの変数は10個を超えると、shiftを使うなど、面倒が生じますが、
事前にパラメタを設計するようなケースでは、パラメタ情報をcsvに用意しておき、
for文で取り出しながら、必要なバッチ処理をまとめて行う、というような処理も作れます。
上の例での注意。
- csvの値に「,」を含めることは出来ません。「,」は区切り文字です。
-
"aa,bbb"の様にして"で囲むことも出来ません。
上の for文は ( ) 内に type コマンドを書きましたが、
下の様に ( ) 内にファイル名を書くこともできます。ただし、この場合は " " で囲んでいないことに注意。
for /F %%a in (for_3.csv) do (
echo %%a
)
ファイル名にスペースを含む場合は " " で囲みたいところですが、
下の様に書くとファイル名そのものが変数に設定されます。
for /F %%a in ("c:\temp\data files\for_3.csv") do (
echo %%a
)
※ この場合は usebackq を付けて for /F "usebackq" %%a in ("c:\temp\data files\for_3.csv")
と書けば、ファイル名として解釈させられる。
改行を入れてコマンドライン引数を複数の行に分けるには、
Linuxの「\」ではなく「^」が使える。
LinuxのBashのEOF(ヒアドキュメント)は、WindowsのBATだと「()」で記述できる、
と言う記述があるがコマンドライン引数には適用できないので、
当該引数がファイル入力をサポートしていないかを確認する。
CALLを使用する。
CALL BATファイル名 引数1 引数2 ...
※ CALL を付けずに別の bat を書くと、呼び出し元には戻らない(プロセスが乗っ取られる)。
for文で do ( ... ) の ( ) 内に複数行に渡って記述できますが、
( ) 内で設定した変数を使用する場合は、変数が展開されるタイミングについて注意が必要です。
@setlocal
@echo off
set csv="%~dpn0.csv"
for /F "tokens=1,2,3,4 delims=," %%a in ('cmd.exe /c type %csv%') do (
set /A var1=%%b + %%c
echo %%b + %%c は %var1%
)
@endlocal
実行例:
bbb + ccc は
33 + 44 は
234 + 456 は
このbatファイルで、echo の %var1% は、for文を開始する直前に置き換えられて、空文字になっています。
以下のbatファイルの様に
-
setlocal ENABLEDELAYEDEXPANSIONを指定して遅延展開を有効にし、 - 変数を
!変数名!と記述します。
@setlocal ENABLEDELAYEDEXPANSION
@echo off
set csv="%~dpn0.csv"
for /F "tokens=1,2,3,4 delims=," %%a in ('cmd.exe /c type %csv%') do (
set /A var1=%%b + %%c
echo %%b + %%c は !var1!
)
@endlocal
実行例:
bbb + ccc は 0
33 + 44 は 77
234 + 456 は 690
遅延展開を有効にすると、!変数名! が現れた時点で値に置き換えられます。
batファイルの終了コードは、exit コマンドと共に指定します。
exit /B コード
ただし、
- exitコマンドはbatファイルが終了するので、
- batファイルの終了箇所で exit を使用します。
@setlocal
@echo off
set exitcode=0
dir c:\tempo
if %ERRORLEVEL% NEQ 0 (
set exitcode=2
echo dirがエラーです
)
exit /B %exitcode%
@endlocal
goto :EOF
このbatファイルは、
- exit の後にある
@endlocalとgoto :EOFは実行されません。 -
exit /Bが endlocal とgoto :EOFを含んだ動作をします。
補足:
exitを/Bなしで使うと CMD プロセスごと終了する。 呼び出し元の bat に戻りたい場合は必ず/Bを付ける。
batファイルの効果的なdebugツールはありません。
- batファイル冒頭の
@echo offをコメントアウトする - echo を随所に埋め込んで、値を表示する
- pause を埋め込んで、その時点で一時停止させてみる
くらいしか方法がありません。debugが終わったら、元に戻すのを忘れないでください。
以下の様に、debug用の echo を用意すると、戻す作業が少し簡単になるかもしれません。
@setlocal
@echo off
call :_debugprint 引数を確認: %1 %2 %3
for /F "delims=" %%a in ('dir "%~1"') do (
echo %%a
)
@endlocal
goto :EOF
:_debugprint
@rem debugが終わったら、echo をコメントアウトする
echo %*
goto :EOF
移行メモ(正誤): 原文の for 文は
for /F "delims=" %%a in ('dir "%~1"') (とdoが抜けていたため構文エラーになる。doを補った。
@setlocal
@echo off
if "%1" == "" (
goto :_end
)
set a=%1
set /A b=%a% - 1
:_next
if NOT %b% GEQ 1 goto :_end
set /A c=%a% / %b% * %b%
if %c% == %a% (
echo %b%
)
set /A b=%b% -1
goto :_next
:_end
@endlocal
goto :EOF
16
8
4
2
1
以下の set /A は、割って掛けることで、割り切れる数値かを確認をしています
(set /A の除算は整数除算なので、割り切れない場合は元の値に戻らない)。
set /A c=%a% / %b% * %b%
@setlocal
@echo off
call :_vcfiles
@endlocal
goto :EOF
:_vcfiles
for %%i in (*.obj *.pcb *.pch *.ncb *.pdb *.ilk *.idb) do echo "%cd%\%%i" && del "%cd%\%%i"
for /D %%i in (*) do (
pushd "%%i"
call :_vcfiles
popd
)
goto :EOF
このbatファイルを実行すると、カレントディレクトリ以下のVC++の中間ファイルを全て削除します。
%cd% はCMDのカレントディレクトリを表す組み込みの変数です。
2つめのfor文でサブディレクトリを列挙して、pushd でカレントディレクトリを記憶しつつ、
サブディレクトリへ移動し、call :_vcfiles で自身を再帰呼び出ししています。
- バッチファイル - Wikipedia
- 知識ゼロからのwindowsバッチファイル超入門
- Windowsバッチまとめ - Qiita
- @IT Tech TIPS - 超入門コマンドプロンプト
Tags: シェル, インフラストラクチャ, Windows
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。