#author("2018-05-26T13:18:42+09:00","default:mat2umoto","mat2umoto")
 ***バッチ処理の終了
 exit、goto :EOF
  
 ***サブルーチン
 call 別コマンド、call ラベル

#contents

*コマンド/バッチのサンプル [#l0f18a09]
**カレントディレクトリのフォルダ名を取得 [#nf97872b]
#code(dosbatch){{
for %%i in (.) do set cdname=%%~ni%%~xi
echo %cdname%
}}
for文のループ変数の展開を利用。

**指定サイズのバイナリファイル作成 [#m7357238]
#code(dosbatch){{
fsutil file createnew <ファイルパス> <サイズ>
}}
サイズはバイト数を10進数で指定。

**ファイルの所有者の一括変更 [#iddd3f08]
#code(dosbatch){{
cd <対象ディレクトリ>
takeown /f * /r
}}

**ファイルのACL(アクセス制御リスト)を一括設定 [#o1e8242a]
指定したユーザをフルコントロールに設定するには
-Windows XPの場合~
#code(dosbatch){{
cacls <対象のフォルダパス> /T /E /P <ユーザ名>:F
}}
-Windows Vistaの場合~
#code(dosbatch){{
icacls <対象フォルダパス> /T /grant <ユーザ名>:F
}}
ファイルの所有者になってないと不可。

**複数階層のフォルダの一括作成 [#tbb9af72]
コマンドライン拡張機能が有効になっていれば、mkdir(md)コマンドで可能。
#code(dosbatch){{
mkdir "C:\test\test2\test3"
}}
Cドライブさえ認識できれば、test、test2、test3のいずれかが存在しなくても自動的に作成される。

**VSSからソースを取得 [#ma63f333]
VSS6.0がインストールされていること。
#code(dosbatch){{
@echo off
setlocal

rem VSSコマンドラインのバイナリのパスを通す
set path="C:\Program Files\Microsoft Visual Studio\COMMON\VSS\win32";%path%

rem VSSデータベースのディレクトリ(srcsafe.iniの場所をSSDIR環境変数に設定)
set SSDIR="C:\VSSDB"

rem 作業ディレクトリの設定を更新せずにカレントディレクトリにファイルを取得する設定
set Force_Dir=No

rem VSS のユーザIDとパスワードを設定
set vss_id=userid
set vss_pw=password

rem 対象プロジェクト
set vss_project=$/TEST

rem 最新バージョンの取得
rem -R   再帰処理
rem -I-  入力要求を回避
rem -GCK チェックサムの比較によって取得を判断
rem -GTU 取得したファイルにチェックイン日付を設定
rem -Y   IDとパスワードの指定
SS Get %vss_project% -R -I- -GCK -GTU -Y%vss_id%,%vss_pw%

endlocal
}}

**VC++6.0でビルド [#e81b6f69]
VC++6.0がインストールされていること。
#code(dosbatch){{
rem VC++6.0でリビルドを行う
rem   プロジェクト/構成を指定した順番でビルドしていく
rem   結果をログファイルに出力する
msdev workspace.dsw /MAKE "prj1 - Win32 Debug" "prj2 - Win32 Debug" /REBUILD /OUT log.txt

rem ビルドエラーを検出(":"と"エラー"は半角!)
findstr /R /C:"エラー [1-9]" log.txt

rem ビルドエラーあり
if %ERRORLEVEL% == 0 (

rem ビルドエラーなし
) else (

)
}}

#code(dosbatch){{
rem ブラウザデータベースを作成する
rem   Debugフォルダに生成されたsbrファイルからbscファイルを生成
bscmake /o .\Debug\hoge.bsc /nologo \Debug\*.sbr
}}

*記法/構文 [#i128b856]
**条件分岐 (IF) [#q5c336cd]
-NOT オプションを使用すると、条件が反転される。

***比較チェック [#ea188206]
 IF [NOT] [/I] 文字列1 比較演算子 文字列2 コマンド

-文字列1と文字列2を比較した結果で分岐。
-文字列1と文字列2がともに数値と判断される場合は、数値の大小比較となる。それ以外の場合は文字列の大小比較(辞書順)。
-ダブルクォーテーションも比較対象。
-/I オプションを使用すると、文字列の大文字小文字を区別せずに比較する。
-使用できる比較演算子
|比較演算子|意味|h
|==|等しい (左辺 == 右辺)|
|EQU|~|
|NEQ|等しくない (左辺 != 右辺)|
|LSS|より小さい (左辺 < 右辺)|
|LEQ|以下 (左辺 <= 右辺)|
|GTR|より大きい (左辺 > 右辺)|
|GEQ|以上 (左辺 >= 右辺)|

***ファイル存在チェック [#wb9834cd]
 IF [NOT] EXIST ファイル名 コマンド

-ファイルが存在するか否かで分岐。

***環境変数の使用チェック [#c8cb2316]
 IF [NOT] DEFINED 変数 コマンド

-環境変数が定義されているか否かで分岐。

***終了コードのチェック [#t7d35b52]
 IF [NOT] ERRORLEVEL 番号 コマンド

-ERRORLEVEL が指定した番号以上か否かで分岐。
-他のIF文やFOR文などのブロック内のIF文で、環境変数のERRORLEVELを使用して評価する場合、「%ERRORLEVEL%」では正しい値を取得することができないため、遅延展開を使用し、「!ERRORLEVEL!」とする必要がある。この構文を用いれば、遅延展開を意識する必要はなくなる。

***コマンドプロンプトの拡張機能のバージョン番号のチェック [#d8b48ec0]
 IF [NOT] CMDEXTVERSION 番号 コマンド

-CMDEXTVERSION が指定した番号以上か否かで分岐。

***IF-ELSE構文 [#re7d8563]
#code(dosbatch){{
IF %VAL% == "TEST1" (
	echo TEST1
) ELSE IF %VAL% == "TEST2" (
	echo TEST2
) ELSE (
	echo ERR
)
}}


**繰返し (FOR) [#t969c332]
-ループ変数
--%a~%z、%A~%Zの52種類使用できる。
--複数の結果を受け取る場合は、次の文字の変数に格納される。(%i を指定して3つの結果を受け取る場合は、%i %j %k に格納される。)
--バッチファイル中で使用する場合は、%%a のように記述する。
--使用時に、コマンドラインパラメータのように展開することができる。
-ファイルセット
--カンマ区切りで複数指定することが可能。
 aaa.txt, bbb.txt
--ワイルドカードを使用して、指定ディレクトリ内を検索させることが可能。
 *.dat

***複数ファイルに対する繰返し処理 [#pc3422e0]
 FOR [/D] %ループ変数 IN (ファイルセット) DO コマンド
-ファイルセットで指定されたファイルパスが順番にループ変数に格納される。
-/D オプションを使用すると、ワイルドカード使用時の検索対象がディレクトリとなる。

***複数ファイルに対する繰返し処理(再帰) [#e22dc199]
 FOR /R [/D] [[ドライブ:]パス] %ループ変数 IN (ファイルセット) DO コマンド
-指定パス以下を再帰的に検索され、ファイルセットで指定された内容に一致するファイルパスが順番にループ変数に格納される。
-/D オプションを使用すると、ワイルドカード使用時の検索対象がディレクトリとなる。

***数値による繰返し処理 [#db316cf7]
 FOR /L %ループ変数 IN (開始,ステップ,終了) DO コマンド
-開始、ステップ、終了で指定された数値が順番にループ変数に格納される。

***複数文字列に対する繰返し処理 [#ke829bfd]
 FOR /F ["解析オプション"] %ループ変数 IN (ファイルセット | "文字列" | 'コマンド') DO コマンド
 FOR /F "USEBACKQ [解析オプション]" %ループ変数 IN ("ファイル セット" | '文字列' | `コマンド`) DO コマンド
-複数の文字列に対して処理を行う。
-ファイルセットの場合は、ファイルの各行の解析結果がループ変数に格納される。
-コマンドの場合は、実行したコマンドの標準出力の各行の解析結果がループ変数に格納される。
-解析オプション
|オプション|説明|h
|usebackq|次の新しい表示形式を指定します。逆引用符で囲まれた&br;文字列がコマンドとして実行され、一重引用符で囲まれた&br;文字列がリテラル文字列コマンドになりファイル名セット&br;のファイル名を二重引用符で囲めるようになります。|
|eol=c|行末のコメント文字を指定します (1 文字)。|
|skip=n|ファイルの先頭でスキップする行数を指定します。|
|delims=xxx|区切り文字のセットを指定します。これは、既定の&br;区切り文字であるスペースとタブを置き換えます。|
|tokens=x,y,m-n|各繰り返しに対して、各行から for 本体に渡すトー&br;クンを指定します。これにより、追加の変数名が割り当&br;てられます。m-n の形式は範囲で、m 番目から n 番目の&br;トークンを指定します。tokens= 文字列の最後の文字が&br;アスタリスクである場合は、追加の変数が割り当てられ、&br;最後のトークンが解析された後、行に含まれている残り&br;のテキストを受け取ります。|

**コメント [#z5ccbb0e]
#code(dosbatch){{
rem コメントの書き方
::  これもコメント
}}
1行コメントのみ。
**エスケープシーケンス [#d1b9e960]
エスケープが必要な文字は、「|><」と改行コード。~
エスケープするには「^」を直前につける。
#code(dosbatch){{
rem |><を出力
echo ^|^>^<
}}

**行の継続 [#c021669e]
行の末尾に「^」を入力することで改行がエスケープされ、コマンドを継続できる。~
コマンドプロンプトでもバッチファイルでも可能。

※ただし、行の継続を行った場合はリダイレクトは使用できない。
**特殊記号のエスケープ [#ndb36c72]
 ^& → &
 ^> → >
 ^< → <
 ^| → |
 ^^ → ^
 %% → %
その他、ある局面において特殊な解釈が行われる文字の直前に「^」を書くことでエスケープできる。

**複数コマンドの組み合わせ [#mc9776aa]
-複数コマンドの実行
#code(dosbatch){{
command1 & command2
}}

-1つ目のコマンドが成功したときのみ処理を継続
#code(dosbatch){{
rem 成功判定はERRORLEVELの値ではなく、コマンド自体にエラーが発生していないか
command1 || command2
}}

-1つ目のコマンドが失敗したときのみ処理を継続
#code(dosbatch){{
rem 成功判定はERRORLEVELの値ではなく、コマンド自体にエラーが発生していないか
command1 && command2
}}

**リダイレクト [#ufc4dafb]
***基本 [#h12cebb8]
「>」「>>」のどちらかを使用する。
#code(dosbatch){{
rem ファイルを新規作成して出力
echo aaa> test.txt

rem ファイルが既に存在する場合は末尾に追記する
rem ファイルが存在しなければ新規作成して出力
echo aaa>> test.txt
}}

下記のように、「> [ファイル名]」という部分は行内のどこへ書いてもよい。(書く場所によっては区切りのために書いた半角SPまでリダイレクトされてしまうので注意)
#code(dosbatch){{
> test.txt echo aaa
}}

***特殊なデバイス [#ffdf9696]
-conデバイス~
標準入出力のためのデバイス。入力として使用するとキーボード、出力として使用するとディスプレイとなる。
#code(dosbatch){{
rem ディスプレイへ出力
echo aaa> con
}}

-nulデバイス~
このデバイスへ出力された内容は破棄される。
#code(dosbatch){{
rem 出力を抑制
echo aaa> nul
}}

***ファイルディスクリプタの指定 [#gdd0076f]
リダイレクト文字の前後に数字を書くと、入出力に用いるファイルディスクリプタを明示的に指定できる。
|数字|意味|h
|0|標準入力(stdin)|
|1|標準出力(stdout)|
|2|標準エラー出力(stderr)|
|3~9|その他の用途に割り当てられる|
#code(dosbatch){{
rem 標準出力と標準エラー出力の両方をtest.txtにリダイレクト
command >test.txt 2>&1
}}

**標準出力 [#l9f6f293]
***空行の出力 [#kfc9d2a8]
#code(dosbatch){{
echo.
}}
※「.」の前後にスペースを入れないこと


***指定コマンドのみ表示抑制 [#ndb40798]
コマンドの先頭に「@」をつけると、そのコマンドの実行シーケンスは表示が抑制される。
#code(dosbatch){{
@pause
}}

***改行しないecho [#k6571324]
echoコマンドを使用した文字列出力は必ず末尾で改行されてしまう。~
改行せずに出力する方法は以下。
#code(dosbatch){{
rem Xは捨て変数
SET /p X=改行無しで出力したい文字列<nul
}}
setコマンドの/pオプションは、文字列を出力して入力待ちを行う。~
そこへnulデバイスからリダイレクトさせることで、入力待ちを解除するという力技。~
どうしても改行せずに文字列出力したい場合に。

**外部コマンドの実行 [#ac71b7ba]
***別のバッチファイルの呼び出し [#v338602c]
-バッチファイルから別のバッチファイルを呼び出す場合、「call」を使用しないと呼び出したバッチファイルの処理の終了時点で全ての処理が終了してしまうので注意。
#code(dosbatch){{
rem sub.batの処理が終了したら次の行から処理を継続する
call sub.bat

rem sub.batの処理が終了したらこのバッチファイルの処理も終了する
sub.bat
}}

-呼び出した別のバッチファイル内で「exit」を使用していると、全ての処理が終了してしまうので注意。


***バッチファイルの戻り値 [#i04af478]
-バッチファイルの呼び出し元に戻り値を返すには、exitコマンドを使用する
#code(dosbatch){{
rem 戻り値=1
exit /b 1
}}
-/b が無いとコマンドプロンプト自体が終了してしまうので注意
-exitコマンドを明示的に呼び出さない場合、ERRORLEVELは変更されない。0クリアされるわけではないことに注意

-呼び出し元で戻り値を参照するには
#code(dosbatch){{
rem バッチファイル呼び出し
call sub.bat

rem 戻り値はif文のERRORLEVEL演算子か、
if ERRORLEVEL 1 (
    rem ERRORLEVEL環境変数で参照可能
    echo %ERRORLEVEL%
)
}}

***コマンドを非同期で実行 [#d1cb0ab6]
単純にコマンドを記述すると、その処理が終了するまで親の処理も待機する。~
startコマンドを用いると、処理の終了を待たずに親の処理が行われる。
#code(dosbatch){{
rem 同期呼び出し
notepad.exe

rem 非同期呼び出し
start notepad.exe
}}

***拡張子を省略 [#wdfe95a4]
実行するコマンドの拡張子は省略できるものがある。(例:exe, bat)~
これは、拡張子が省略されたコマンドが実行された場合に、環境変数「PATHEXT」に登録されている拡張子を登録されている順番で付与していき、最初に存在するファイルを実行する仕組みになっているためである。

**環境変数 [#y3c69d45]
***バッチファイル上での環境変数の使用 [#rc5d64b8]
そのバッチファイル上でのみ有効な環境変数となる。~
バッチファイルの外には影響を与えない。

***環境変数の局所化 [#aa9119b1]
#code(dosbatch){{
setlocal

endlocal
}}
「setlocal」と「endlocal」で挟まれた範囲では、環境変数を局所的に使用できる。~
範囲外のコマンドに影響を与えずに環境変数の利用ができる。

***環境変数の遅延展開 [#w9a66b3e]
以下のようなコードでは、環境変数の展開が期待した通りにならない。
#code(dosbatch){{
set x="123"
if %x% == "123" (
	set x="456"
	echo %x%
)
}}
→echoにより"123"が表示されてしまう。~

バッチファイルのコードの評価がデフォルトで即時展開になっている。つまり、行単位ではなくコマンド単位で評価・展開されるために、上記のような状態となってしまう。~
即時展開の場合は、ifコマンド全体が一度に評価・展開されるため、展開後のコードは以下の状態となってしまう。
#code(dosbatch){{
set x="123"
if "123" == "123" (
	set x="456"
	echo "123"
)
}}

これを防ぐために環境変数の遅延展開を用いることができる。~
「setlocal ENABLEDELAYEDEXPANSION」~「endlocal」で挟まれたコードは、「%」の替わりに「!」を用いることで、即時展開を避けることができる。
#code(dosbatch){{
setlocal ENABLEDELAYEDEXPANSION
set x="123"
if %x% == "123" (
	set x="456"
	echo !x!
)
endlocal
}}
→echoにより"456"が表示される。~

***配列風に環境変数を使用する [#ab626ae0]
以下のように記述することで、C言語の配列風に環境変数を使用できる。~
(実際には、配列のカッコと添え字まで含めて1つの変数名として扱われている。)~

ans[0]に対する設定/参照を例に用いる。i には予め 0 が代入されているものとする。~

-記述例~
||配列の操作|記述例|h
|①添え字を直接数字で指定|設定|set x[0]=10|
|~|参照|echo %x[0]%&br;set y=%x[0]%|
|②添え字を変数iで指定&br;(callを使用)|設定|set x[%i%]=10|
|~|参照|call echo %&#x25;x[%i%]%&#x25;&br;call set y=%&#x25;x[%i%]%&#x25;|
|③添え字を変数iで指定&br;(遅延展開を使用)|設定|set x[%i%]=10|
|~|参照|echo !x[%i%]!&br;set y=!x[%i%]!|
※遅延展開を使用する場合は、「setlocal ENABLEDELAYEDEXPANSION」を記述するのを忘れないように。

-②の理屈~
記述した内容~
 call echo %%x[%i%]%%
「%%」はエスケープされて「%」に、「%i%」は変数の参照として評価されて「0」に展開される。~
 call echo %x[0]%
callがあることで、さらにechoコマンドの子プロセス内で「%x[0]%」が変数の参照として評価される。~
もしcallがなければ、「%x[0]%」という文字列がそのままechoにより表示されてしまうことになる。~

***動的な環境変数 [#t78e3cf5]
|動的な環境変数|説明|h
|%CD%|カレントディレクトリのフルパス|
|%DATE%|現在の日付&br;(例) 2012/06/13|
|%TIME%|現在の時刻&br;(例) 16:47:41.89|
|%RANDOM%|0~32767の乱数|
|%ERRORLEVEL%|現在の ERRORLEVEL|
|%CMDEXTVERSION%|コマンドプロンプトの拡張機能のバージョン番号|
|%CMDCMDLINE%|コマンドプロンプトが起動されたときのコマンドライン文字列|

***環境変数の算術演算 [#q414e534]
#code(dosbatch){{
rem 環境変数を%や!で囲む必要がない
set /a cnt=cnt+1
}}

-使用できる演算子
|優先度|演算子|用途|h
|CENTER:(高)&br;↑&br;↓&br;(低)|()|グループ化|
|~|! ~ -|単項演算子|
|~|* / %|算術演算子|
|~|+ -|算術演算子|
|~|<< >>|論理シフト|
|~|&|ビット演算子 AND|
|~|^|ビット演算子 XOR|
|~|&#x7c;|ビット演算子 OR|
|~| = *= /= %= += -=&br;&= ^= &#x7c;= <<= >>=|代入|
|~|,|式の区切り記号|

-8進数、16進数の使用
 10     10進数
 012     8進数
 0x1A   16進数

***パラメータの展開 [#q1129b11]
コマンドラインのパラメータである %0~%9 や、FOR文のパラメータ(%%iなど)は、文字列を展開させることができる。
|オプション構文|説明|例 (カレントディレクトリは C:\FOLDER とする)|h
|%~1|すべての引用句 (") を削除して、%1 を展開します。|"FILE.EXT"&br;→FILE.EXT|
|%~f1|%1 を完全修飾パス名に展開します。|"FILE.EXT"&br;→C:\FOLDER\FILE.EXT|
|%~d1|%1 をドライブ文字だけに展開します。|"FILE.EXT"&br;→C:|
|%~p1|%1 をパスだけに展開します。|"FILE.EXT"&br;→\FOLDER\|
|%~n1|%1 をファイル名だけに展開します。|"FILE.EXT"&br;→FILE|
|%~x1|%1 をファイル拡張子だけに展開します。|"FILE.EXT"&br;→.EXT|
|%~s1|展開されたパスは、短い名前だけを含みます。||
|%~a1|%1 をファイル属性に展開します。|"FILE.EXT"&br;→--a------|
|%~t1|%1 をファイルの日付/時刻に展開します。|"FILE.EXT"&br;→2012/6/12  16:12:00|
|%~z1|%1 をファイルのサイズに展開します。(バイト)|"FILE.EXT"&br;→124|
|%~$PATH:1|PATH 環境変数に指定されているディレクトリを&br;検索し、最初に見つかった完全修飾名に %1 を&br;展開します。環境変数名が定義されていない場合、&br;または検索してもファイルが見つからなかった&br;場合は、この修飾子を指定すると空の文字列に&br;展開されます。|"CMD.EXE"&br;→C:\WINDOWS\system32\cmd.exe|

また、以下のようにオプションを組み合わせることも可能。
|オプション構文|説明|例 (カレントディレクトリは C:\FOLDER とする)|h
|%~dp1|%1 をドライブ文字とパスだけに展開します。|"FILE.EXT"&br;→C:\FOLDER\|
|%~nx1|%1 をファイル名と拡張子だけに展開します。|"C:\FOLDER\FILE.EXT"&br;→FILE.EXT|
|%~ftza1|%1 を DIR の出力行のように展開します。|"FILE.EXT"&br;→--a------ 2012/06/12 16:12 124 C:\Current\TMP\TMP\FILE.EXT|

***文字列置換 [#fbd46e28]
変数src内の "abc" を "xyz" に置換する例。
 set src=abcdefg
 set dst=%src:abc=xyz%
 rem dst は "xyzdefg" となる

*注意点 [#q6dd5145]
**拡張子の扱い [#y3cc6a35]
MS-DOSの定義では、拡張子は「0文字以上3文字以下」であるため、4文字目以降は無視される。~
例えば、以下のコマンドを実行すると「hoge.abcd」というファイルも削除されてしまう。
#code(dosbatch){{
del *.abc
}}

**無限ループ [#a12d3f2c]
バッチファイルに、ファイル中で使用するコマンドと同じ名前を付けて実行すると、再帰コールし続けてしまうことになる。~
(使用したかったコマンドではなく、自分自身の呼び出しが優先されてしまうため)~

1行だけコマンドを記述した単純なバッチファイルを作るときに、うっかり上記のようなファイル名にしてしまいがちなので、注意。

**echoで最後の数字が正しく出力されない現象 [#d8aadabe]
リダイレクト文字の直前に数字がある場合はファイルディスクリプタ番号の指定であると解釈され、期待通りに動作しない。
#code(dosbatch){{
rem 問題:"aaa,1"という文字列を出力したいが"aaa,"になってしまう
echo aaa,1> test.txt

rem 対処1:リダイレクト指定の行内での場所を変える(「>」の直前に数字がこないようにする)
> test.txt echo aaa,1

rem 対処2:数字をエスケープする(文字としての数字であると認識させる)
echo aaa,^1> test.txt
}}

**setコマンドで入力待機する際のプロンプトにカーソルが被ってしまう現象 [#j662a8e9]
setコマンドで入力待機する際、表示するプロンプト文字列に全角SPを使用すると、使用した数だけカーソルがずれてしまう。~
全角SPは使用しない方がよい。
#code(dosbatch){{
rem 例
set /p test="文字列を入力してください :"
}}


トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS