とほほのバッチ入門

トップ > バッチ

目次

はじめに

PowerShell も浸透してきているのに今更感がありますが、リクエストを受けたので Windows バッチの機能について整理しました。

拡張子

バッチファイルの拡張子は *.BAT です。

文字コード

デフォルトのコマンドプロンプトの文字コードは CP932 (Microsoft版 Shift_JIS) になっています。バッチファイルも CP932 (メモ帳で保存する時は ANSI を指定) で作成する必要があります。UTF-8 のバッチファイルを実行するにはコードページ変更コマンド chcp を用います。

chcp 932		# CP932(Shift_JIS)モードにする
chcp 65001		# UTF-8モードにする

引数

バッチファイルへの引数は %1, %2, %3, ..., %9 で参照できます。%0 はコマンド名を示します。10個以上の引数を扱うには forshift を用います。

echo コマンドは %0 です。
echo 第1引数は %1 です。
echo 第2引数は %2 です。
echo 第3引数は %3 です。

%~1 %~2 の様に % と数字の間に ~ をつけると、引数が "..." で囲まれていればそれを除去します。"C:\Program Files\..." など空白の入った文字列を渡す際に有効です。

echo "%~1"

SHIFT

文法
shift [/n]

shift は引数をシフトします。shift を実行すると %2%1%3%2 ... にシフトします。

echo %1		:1番目の引数を表示
shift
echo %1		:2番目の引数を表示
shift
echo %1		:3番目の引数を表示

/n を指定すると n番目の引数からシフトするようになります。例えば、/2 を指定すると %0%1 はそのままで、%3%2 に、%4%3 ... にシフトします。

echo %0 %1 %2 %3 %4	:0, 1, 2, 3, 4番目の引数を表示
shift /2
echo %0 %1 %2 %3 %4	:0, 1, 3, 4, 5番目の引数を表示

ECHO OFF

バッチを実行すると実行するコマンドが表示されますが、コマンドの先頭に @ をつけると表示しなくなります。

date /T		:コマンドが表示される
@date /T	:コマンドが表示されない

echo off は以降のコマンドを表示しないようにします。@echo off を指定することで、echo off コマンド自体も表示せず、以降のコマンドも表示しなくなります。

@echo off

SET

文法
set
set VariableName=Value
set VariableName=

set は環境変数に値を設定します。

set name=Yamada

set のみを実行すると、環境変数の一覧を表示します。

set

環境変数を表示するには、環境変数名を %...% で囲みます。

echo %name%

環境変数をクリアするには下記の様にします。

set name=

SETLOCAL・ENDLOCAL

文法
setlocal [Option]
endlocal
Option ::= ENABLEEXTENSIONS | DISABLEEXTENSIONS | ENABLEDELAYEDEXPANSION | DISABLEDELAYEDEXPANSION

set で設定する変数はグローバル変数として設定されますが、setlocalendlocal の間で設定される変数はローカル変数として扱われます。

set a1=123			# グローバル変数
setlocal
set a2=456			# ローカル変数
echo %a1% %a2%			# 両方とも参照できる
endlocal
echo %a1% %a2%			# ローカル変数は参照できない

グローバル変数はバッチの実行完了後でもコマンドプロンプトの環境変数として残ってしまいます。

C:\>echo %name%
%name%			# 変数nameは未定義
C:\>test.bat		# 変数nameを使用するバッチを実行
C:\>echo %name%		# 変数nameの定義が残ってしまう
Yamada

バッチの中で使用した変数が実行後に悪影響を与えないよう、変数を使用するバッチは startlocal...endlocal で囲んでおいた方が無難です。

@echo off
setlocal
  :
endlocal

REM

文法
rem Comment

rem はコメントを記載します。

rem ここにコメントを記述します

ラベル

文法
:Label

コロン(:)はラベルを定義します。ラベルは gotocall の呼び先として参照されます。

:labelA
echo BBB

ラベルをコメントの代わりに使用することもできます。

:ここにコメントを記述します

GOTO文

文法
goto Label

goto 文は指定したラベルの位置にジャンプします。下記の例では goto の箇所で :labelA にジャンプし、AAA と CCC が表示されます。

echo AAA
goto labelA
echo BBB

:labelA
echo CCC

CALL文

文法
call Command
call :Label

call は外部コマンドや外部バッチを呼び出します。呼び出しには引数を指定することができます。

call example2.bat arg1 arg2 srg3
サブルーチン

CALL と ラベルを用いてサブルーチンを実現することができます。

call :funcA "ABC" 123
call :funcB "XYZ" 456
exit /B 0

:funcA
   echo funcA(%1, %2)
   exit /B 0

:funcB
   echo funcB(%1, %2)
   exit /B 0

START文

文法
start ["Title"] [Options] Command
  Options ::=
    /D PathName
    /B
    /I
    /MIN
    /MAX
    /WAIT

start も外部コマンドや外部バッチを呼び出します。call とは異なり、別のコマンドプロンプトが別プロセスとして起動します。

start example2.bat arg1 arg2 arg3

"..." を指定すると、別ウィンドウのタイトルを指定することができます。

start "Some Title..." example2.bat arg1 arg2 arg3

/D オプションは別ウィンドウのカレントディレクトリを指定します。

start /D C:\Temp example2.bat arg1 arg2 arg3

/B オプションは別ウィンドウを開かずに同じウィンドウの中でコマンドを実行します。

start /B example2.bat arg1 arg2 arg3

/MIN は別ウィンドウを最小化状態で、/MAX は別ウィンドウを最大化状態で開きます。

start /MIN example2.bat arg1 arg2 arg3
start /MAX example2.bat arg1 arg2 arg3

/WAIT は start で呼び出したコマンドが終了するのを待ち合わせします。

start /WAIT example2.bat arg1 arg2 arg3

EXIT文

文法
exit [/B] [ExitCode]

バッチやコマンドプロンプトを終了します。

exit

ExitCode には -2147483648~2147483647 の整数を指定することができます。

exit 123

ExitCode の値は %ERRORLEVEL% で参照することができます。

C:\> echo %ERRORLEVEL%
123

/B オプションを指定するとバッチだけが終了し、バッチを起動したコマンドプロンプトは残ります。

exit /B

IF文

文法
if Condition Command
if Condition ( Commands... )
if Condition ( Commands... ) else ( Commands... )
if Condition ( Commands... ) [else if Condition ( Commands... )]... else ( Commands... )
Condition ::=
  [not] [/i] Value1==Value2
  [not] exist FileName
  [not] defined VariableName
  [/i] Value1 Ope Value2
Ope ::=
  equ | neq | gtr | geq | lss | leq

if 文は、条件式が真の時にコマンドを実行します。

set name=Yoshida
if %name%==Yamada echo Yamadaです

not をつけると条件式が偽の時にコマンドを実行します。

if not %name%==Yamada echo Yamadaではありません

/i をつけると文字列比較で大文字・小文字を区別しなくなります。

if /i %name%==Yamada echo Yamadaです

name が未定義の時にもエラーにならないようにするには "..." で囲んで比較します。

if "%name%"=="Yamada" echo Yamadaです

下記の様に ( ... ) を用いることで複数のコマンドを実行することができます。

if %name%==Yamada (
    echo Yamadaです
    echo Yamadaです
) else (
    echo Yamadaではありません
    echo Yamadaではありません
)

else if を用いることもできます。

if %name%==Yamada (
  echo Yamadaです
) else if %name%==Suzuki (
  echo Suzukiです
) else (
  echo YamadaでもSuzukiでもありません
)

数値の比較には equ などの演算子を用います。not は使用できません。

set n=10
if %n% equ 10 echo 10です
if %n% neq 5  echo 5ではありません
if %n% gtr 9  echo 9よりも大きな数字です
if %n% geq 9  echo 9以上の数字です
if %n% lss 11 echo 11よりも小さな数字です
if %n% leq 11 echo 11以下の数字です

ファイルの存在有無を確認するには exist を用います。

if exist C:\Temp\test.txt echo ファイルがあります。
if not exist C:\Temp\test.txt echo ファイルが有りません。

変数が定義されているかを確認するには defined を用います。

if defined XXXX_HOME echo 定義されてます
if not defined XXXX_HOME echo 定義されていません

FOR文

文法
for %%v in (files) do ( Commands )
for /R %%v in (files) do ( Commands )
for /D %%v in (directories) do ( Commands )
for /L %%v in (start, increment, end) do ( Commands )
for /F ["FOptions"] %%v in (file) do ( Commands )
for /F ["FOptions"] %%v in ('Command') do ( Commands )
FOptions ::=
  delims=string
  tokens=n, ...
  skip=n
  eol=string
  usebackq
ファイル・ディレクトリループ

for文は対象のファイル群に対してループ処理を行います。変数名は1文字に限られます。ファイルは空白デリミタで複数指定できます。

for %%f in (*.txt) do (
    echo %%f
)

/R を指定するとサブフォルダを含めて再帰的にファイルを検索します。

for /R %%f in (*.txt) do (
    echo %%f
)

/D を指定するとファイルではなくディレクトリを対象に処理を行います。

for /D %%d in (a*) do (
    echo %%d
)
引数ループ

下記の様にするとコマンド引数に対してループ処理を行います。

for %%a in (%*) do (
    echo %%a
)
N回ループ

/L を指定すると N回ループを実現できます。(...) の中には、初期値、増分、終了値を指定します。

for /L %%n in (1, 1, 10) do (
    echo %%n
)
ファイルの中身に対するループ

/F を指定すると (...) で指定したファイルの中身の1行1行に対してループを実行します。

for /F %%a in (xx.csv) do (
    echo %%a
)

delims はトークンの区切り文字、tokens は参照するトークン番号を指定します。下記の例では区切り文字に , を指定し、第1トークンを %%a、第2トークンを %%b として参照します。

for /F "delims=, tokens=1,2" %%a in (sample.csv) do (
    echo %%a / %%b
)

skip は先頭行から指定した行数分無視します。下記の例では CSV ファイルの先頭行をヘッダ行とみなして無視します。

for /F "skip=1 delims=, tokens=1,2" %%a in (sample.csv) do (
    echo %%a / %%b
)

eol は指定した文字で始まる行を無視します。下記の例では # で始まる行をコメント行とみなして無視します。

for /F "eol=#" %%a in (sample.txt) do (
    echo %%a
)
コマンドの実行結果に対するループ

/F 指定時にファイル名を '...' で囲むと、... で指定したコマンドの実行結果の1行1行に対してループを実行します。

for /F %%a in ('dir /b') do (
    echo %%a
)

usebackq はコマンドの実行結果を処理する際に '...' の代わりにバッククォート `...` をしようします。

for /F "usebackq" %%a in (`dir /b`) do (
    echo %%a
)
ループの中で変数を参照する際の注意

FOR文の中で変数を参照するには注意が必要です。下記の様にループの中で %name% を参照しても最初に FOR文を評価する時点で変数が展開されてしまうためうまく参照できません。

for /L %%n in (1, 1, 3) do (
    set name=Yamada%%n
    echo My name is %name%
)

この問題を解決するにはループを setlocal enabledelayedexpansion ... endlocal で囲み、変数参照時の %! に変更することで、FOR文実行時に遅延展開させることができます。

setlocal enabledelayedexpansion
for /L %%n in (1, 1, 3) do (
    set name=Yamada%%n
    echo My name is !name!
)
endlocal

配列

配列はサポートされていませんが、変数名に [ や ] も使用できるので、配列っぽく見せることはできます。下記は正確には配列ではなく、a[0] という名前の変数を定義して参照しています。

set a[0]=foo
set a[1]=baa
set a[2]=baz

echo %a[0]%		# foo
echo %a[1]%		# baa
echo %a[2]%		# baz

call を用いると変数が展開されることを利用して、下記の様にループの中で変数名を生成することもできます。

set a[0]=foo
set a[1]=baa
set a[2]=baz

for /L %%i in (0, 1, 2) do (
    call echo a[%%i]=%%a[%%i]%%
)

環境変数

PATH

コマンドを検索する対象フォルダのリストを保持します。デリミタはセミコロン(;)です。

Path=C:\Windows;C:\Windows\system32;
ERRORLEVEL

直前に終了したコマンドの終了コードを示します。通常、0 は成功、0 以外はエラーを意味します。

if %errorlevel% == 0 (
    echo OK
) else (
    echo NG
)
PROMPT

コマンドプロンプトを指定します。

set PROMPT=$P$G
$N    現在のドライブ名。
$P    現在のドライブ名とパス名。
$D    現在の日付。
$T    現在の時刻。
$V    Windowsバージョン。
$A    アンパサンド(&)。
$B    パイプ記号(|)。
$L    小なり不等号(<)
$G    大なり不等号(>)
$Q    等号(=)
$F    右括弧())
$C    左括弧(()
$H    バックスペース(BS)
$$    ドル記号($)
$S    半角スペース( )
$E    エスケープコード(\x1B)
$_    改行文字(CR LF)
RANDOM

0~32767 の乱数を発生させます。

echo %RANDOM%
18703
その他の環境変数
CommonProgramFiles	# 共通プログラムフォルダ(例:C:\Program Files\Common Files)
CommonProgramFiles(x86)	# 共通プログラムフォルダ(32ビット用)(例:C:\Program Files (x86)\Common Files)
CommonProgramW6432	# 共通プログラムフォルダ(32/64ビット共用)(例:C:\Program Files\Common Files)
COMPUTERNAME		# コンピュータ名(例:MYCOMPUTER)
ComSpec			# コマンドプロンプトプログラム(例:C:\WINDOWS\system32\cmd.exe)
DriverData		# ドライバデータフォルダ(例:C:\Windows\System32\Drivers\DriverData)
HOMEDRIVE		# ホームドライブ(例:C:)
HOMEPATH		# ホームフォルダのパス名(例:\Users\tanaka)
LOCALAPPDATA		# アプリケーションデータフォルダ(例:C:\Users\tanaka\AppData\Local)
LOGONSERVER		# ログオンサーバ名(例:\\MYCOMPUTER)
NUMBER_OF_PROCESSORS	# プロセス数(例:12)
OneDrive		# OneDriveのパス名(例:C:\Users\tanaka\OneDrive)
OneDriveConsumer	# OneDriveの個人アカウントパス(例:C:\Users\tanaka\OneDrive)
OS			# OS種別(例:Windows_NT)
PATHEXT			# 実行可能ファイルの拡張子(例:.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC)
PROCESSOR_ARCHITECTURE	# プロセッサアーキテクチャ(例:AMD64)
PROCESSOR_IDENTIFIER	# プロセッサ識別子(例:Intel64 Family 6 Model 165 Stepping 5, GenuineIntel)
PROCESSOR_LEVEL		# プロセッサレベル(例:6)
PROCESSOR_REVISION	# プロセッサリビジョン(例:a505)
ProgramData		# プログラムデータフォルダ(例:C:\ProgramData)
ProgramFiles		# プログラムフォルダ(例:C:\Program Files)
ProgramFiles(x86)	# プログラムフォルダ(32ビット用)(例:C:\Program Files (x86))
ProgramW6432		# プログラムフォルダ(32/64ビット共用)(例:C:\Program Files)
PSModulePath		# PowerShellモジュール(例:C:\Program Files\WindowsPowerShell\Modules)
PUBLIC			# パブリックフォルダ(例:C:\Users\Public)
SESSIONNAME		# セッション名(例:Console)
SystemDrive		# システムドライブ名(例:C:)
SystemRoot		# システムルートフォルダ(例:C:\WINDOWS)
TEMP			# テンポラリフォルダ(例:C:\Users\tanaka\AppData\Local\Temp)
TMP			# テンポラリフォルダ(例:C:\Users\tanaka\AppData\Local\Temp)
USERDOMAIN		# ユーザドメイン(例:MYDOMAIN)
USERNAME		# ユーザ名(例:tanaka)
USERPROFILE		# ユーザプロファイルフォルダ(例:C:\Users\tanaka)
windir			# Winodwsフォルダ(例:C:\WINDOWS)

Copyright (C) 2022-2023 杜甫々
初版:2022年12月18日 最終更新:2023年9月3日
http://www.tohoho-web.com/ex/bat.html