バッチファイルの文字列比較は「完全一致の if ==」だけではありません。大文字小文字の無視・部分一致・前方一致・空文字チェック・未定義変数への対応まで、用途に合わせた手法があります。また変数展開の仕組みを理解していないと思わぬバグを踏みます。この記事ではよくある落とし穴も含めて体系的に解説します。
if "A"=="B"の完全一致比較と書き方のルール/iオプションで大文字小文字を無視する方法findstrによる部分一致・前方一致・後方一致・正規表現- 空文字・未定義変数を安全に比較する方法
- 数値と文字列の比較の違い(落とし穴)
- AND / OR を使った複合条件
- 変数内に
!や%を含む場合の注意点 - PowerShell を使った高度なパターンマッチ
- 実践例3本(引数チェック・環境判定・ファイル種別振り分け)
1. 完全一致比較:if == の基本
バッチファイルの文字列比較は if "値1"=="値2" で行います。必ずダブルクォートで囲むのが重要です。
@echo off
setlocal
set STR1=hello
set STR2=hello
if "%STR1%"=="%STR2%" (
echo 一致しました
) else (
echo 一致しません
)
if %STR1%==%STR2% のようにクォートなしで書くと、変数が空の場合に if =="" となり構文エラーになります。また値にスペースを含む場合も正しく動作しません。常に if "%VAR%"=="値" の形式で書いてください。1-1. 否定比較(一致しない場合)
@echo off
setlocal
set ENV=production
:: NOT で否定
if not "%ENV%"=="production" (
echo 本番環境ではありません
exit /b 1
)
echo 本番環境で実行します
1-2. 複数の値と順番に比較する(else if チェーン)
@echo off setlocal set MODE=%~1 if "%MODE%"=="start" goto :do_start if "%MODE%"=="stop" goto :do_stop if "%MODE%"=="restart" goto :do_restart echo [ERROR] 不明なモード: %MODE% echo 使い方: %~nx0 start^|stop^|restart exit /b 1 :do_start echo サービスを起動します exit /b 0 :do_stop echo サービスを停止します exit /b 0 :do_restart echo サービスを再起動します exit /b 0
2. 大文字小文字を無視して比較する:/i オプション
if /i を使うと大文字小文字を区別せずに比較できます。ユーザー入力の Y/N 確認・コマンド引数のチェックなど、大文字小文字がゆれやすい場面で必須です。
@echo off
setlocal
:: /i で大文字小文字を無視
set /p ANSWER=続行しますか? (Y/N):
if /i "%ANSWER%"=="y" (
echo 続行します
) else if /i "%ANSWER%"=="yes" (
echo 続行します
) else (
echo キャンセルしました
exit /b 0
)
if /i は == による文字列比較にのみ有効です。findstr の大文字小文字無視には別途 /i オプションが必要です(後述)。また if /i は日本語の大文字小文字変換は行いません(ASCII 範囲のみ)。2-1. コマンドライン引数を大文字小文字無視でチェックする
@echo off
setlocal
:: --dry-run / --DRY-RUN / --Dry-Run すべてを受け付ける
set DRY_RUN=0
for %%A in (%*) do (
if /i "%%A"=="--dry-run" set DRY_RUN=1
if /i "%%A"=="--dryrun" set DRY_RUN=1
if /i "%%A"=="--dry" set DRY_RUN=1
)
if "%DRY_RUN%"=="1" (
echo [DRY-RUN] 変更は行いません
) else (
echo 実際に処理を実行します
)
3. 空文字・未定義変数を安全にチェックする
変数が未定義または空文字のまま比較すると構文エラーになる場合があります。安全なチェック方法を覚えておきましょう。
| 状況 | 安全な書き方 | 注意点 |
|---|---|---|
| 変数が空かどうかチェック | if "%VAR%"=="" |
ダブルクォートで囲む |
| 変数が未定義かどうかチェック | if not defined VAR |
defined は % 不要 |
| 変数が定義済みかチェック | if defined VAR |
空文字は defined で真になる |
| 空または未定義を同時にチェック | if "%VAR%"=="" または not defined |
2行に分けて書く |
@echo off
setlocal
:: 未定義チェック(defined キーワードを使う)
if not defined INPUT_FILE (
echo [ERROR] INPUT_FILE が設定されていません
exit /b 1
)
:: 空文字チェック(ダブルクォートで囲む)
if "%INPUT_FILE%"=="" (
echo [ERROR] INPUT_FILE が空です
exit /b 1
)
:: 未定義または空を一度にチェック
if not defined INPUT_FILE goto :err_empty
if "%INPUT_FILE%"=="" goto :err_empty
echo INPUT_FILE = %INPUT_FILE%
goto :eof
:err_empty
echo [ERROR] INPUT_FILE を指定してください
exit /b 1
if defined VAR は変数が定義されているかをチェックします。set VAR=(空文字代入)すると VAR は定義済みになるため if defined VAR は真になりますが、if "%VAR%"=="" は偽になります。「未設定のままにしてほしい」変数には両方のチェックを組み合わせてください。4. 部分一致・前方一致・後方一致:findstr との組み合わせ
if == は完全一致のみです。「〜を含む」「〜で始まる」「〜で終わる」のチェックには findstr を使います。
4-1. 部分一致(文字列が含まれるか)
@echo off
setlocal
set STR=C:\Program Files\MyApp\app.exe
:: "Program Files" が含まれるか
echo %STR% | findstr /i /c:"Program Files" >nul
if %errorlevel% equ 0 (
echo "Program Files" が含まれています
) else (
echo 含まれていません
)
4-2. 前方一致(〜で始まる)
@echo off
setlocal
set FILENAME=report_2025_03.csv
:: "report_" で始まるか(findstr /r で正規表現を使う)
echo %FILENAME% | findstr /r /c:"^report_" >nul
if %errorlevel% equ 0 (
echo "report_" で始まっています
) else (
echo 前方一致しません
)
:: 純バッチで前方一致(文字列切り出しを使う方法)
:: 先頭7文字を切り出して比較
if /i "%FILENAME:~0,7%"=="report_" (
echo "report_" で始まっています(切り出し比較)
)
%VAR:~0,n% で先頭 n 文字を切り出して if == で比較する方法は、外部コマンドを呼ばないためループ内でも高速です。文字数が固定の前方一致チェックに最適です。文字列操作の詳細は「文字列を切り出して抽出する方法」も参照してください。4-3. 後方一致(〜で終わる)
@echo off
setlocal
set FILENAME=data_backup.tar.gz
:: ".gz" で終わるか(findstr /r で正規表現)
echo %FILENAME% | findstr /r /c:"\.gz$" >nul
if %errorlevel% equ 0 (
echo .gz ファイルです
)
:: 拡張子チェックは %%~xF 変数が簡単
set EXT=%FILENAME:~-3%
if /i "%EXT%"==".gz" echo .gz ファイルです(切り出し比較)
:: for ループなら %%~xF で拡張子を直接取得できる
for %%F in ("%FILENAME%") do (
if /i "%%~xF"==".gz" echo .gz ファイルです(%%~xF 比較)
)
4-4. 正規表現で高度なパターンマッチ
@echo off
setlocal
set STR=order_20250317_001.csv
:: "order_" + 8桁の日付 + "_" + 3桁数字 + ".csv" の形式か確認
echo %STR% | findstr /r /c:"^order_[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]_[0-9][0-9][0-9]\.csv$" >nul
if %errorlevel% equ 0 (
echo 正しいファイル名形式です
) else (
echo ファイル名形式が不正です
)
:: メールアドレス形式チェック(簡易)
set MAIL=user@example.com
echo %MAIL% | findstr /r /c:"^[a-zA-Z0-9._-][a-zA-Z0-9._-]*@[a-zA-Z0-9.-][a-zA-Z0-9.-]*\.[a-zA-Z][a-zA-Z]*$" >nul
if %errorlevel% equ 0 (
echo 有効なメールアドレス形式です
) else (
echo メールアドレス形式が不正です
)
findstr の正規表現・複数条件・ファイル検索の詳細は FINDSTRコマンド完全ガイド を参照してください。
5. 数値比較と文字列比較の違い(重要な落とし穴)
if "10"=="9" は偽(10 と 9 は違う文字列)ですが、if "10" gtr "9" も文字列として比較するため偽になります(”1″ < “9”)。数値の大小比較には必ず if %NUM% gtr 9(クォートなし整数比較)を使ってください。@echo off
setlocal
:: 文字列比較(== は文字列として比較)
if "10"=="10" echo 文字列 "10" は一致
if "10"=="9" echo これは表示されない(文字列として異なる)
:: 文字列の辞書順比較(lss/gtr)
if "10" lss "9" echo "10" は "9" より辞書順で小さい ← これが表示される!
:: 数値比較(クォートなし整数として比較)
set NUM=10
if %NUM% gtr 9 echo %NUM% は 9 より大きい ← 正しい数値比較
:: 数値かどうか不明な変数の安全な比較
:: set /a で数値変換を試みて errorlevel でチェック
set TEST_VAL=abc
set /a CHECK_NUM=%TEST_VAL% >nul 2>&1
if %errorlevel% neq 0 (
echo %TEST_VAL% は数値ではありません
)
数値の大小比較(EQU/NEQ/GTR/LSS/GEQ/LEQ)の詳細は 数値を比較する方法完全ガイド を参照してください。
6. 複合条件(AND / OR)で複数の文字列を同時チェック
6-1. AND 条件(両方一致)
@echo off
setlocal
:: AND: 2つの条件が両方真のとき
set ENV=production
set MODE=deploy
:: if を入れ子にして AND を表現
if "%ENV%"=="production" (
if "%MODE%"=="deploy" (
echo 本番環境へのデプロイを実行します
)
)
6-2. OR 条件(どちらか一致)
@echo off
setlocal
:: OR: フラグ変数で実現する
set EXT=%~x1
set VALID=0
if /i "%EXT%"==".csv" set VALID=1
if /i "%EXT%"==".tsv" set VALID=1
if /i "%EXT%"==".txt" set VALID=1
if "%VALID%"=="1" (
echo 対応ファイル形式: %EXT%
) else (
echo [ERROR] 非対応の拡張子: %EXT%
exit /b 1
)
:: OR を findstr で表現(パイプ区切り)
echo %EXT% | findstr /i /r /c:"\.csv$" /c:"\.tsv$" /c:"\.txt$" >nul
if %errorlevel% equ 0 echo 対応拡張子です
6-3. NOT AND(除外条件)
@echo off
setlocal
:: 本番環境でかつ dry-run モードでない場合だけ実行
set ENV=production
set DRY_RUN=0
if "%ENV%"=="production" (
if "%DRY_RUN%"=="0" (
echo 本番に実際の変更を加えます
) else (
echo [DRY-RUN] 変更はスキップします
)
)
AND/OR を使った条件分岐の詳細は 条件分岐する方法完全ガイド も参照してください。
7. 変数展開の落とし穴と対処法
7-1. 値に ! や % が含まれる場合
@echo off
setlocal enabledelayedexpansion
:: 遅延展開が有効なとき、値に ! が含まれると展開されて消える
set STR=Hello!World
echo !STR!
:: ↑ "HelloWorld" になる(! が消える)
echo %STR%
:: ↑ "Hello!World" になる(こちらは正常)
:: % を含む値の比較
set STR2=100%%
if "%STR2%"=="100%%" (
echo 100%% と一致しました
)
setlocal enabledelayedexpansion が有効なとき、変数の値に !(感嘆符)が含まれると !VAR! の内側の ! として解釈されます。パスワード・メッセージなど特殊文字を含む値を比較する場合は %VAR% で参照してください。7-2. 変数に余分な空白が混入して比較が失敗する
@echo off setlocal :: set 行末にスペースが入ると変数に空白が含まれる set VAR=hello :: ↑ここにスペースがあると比較が失敗する :: NG: 末尾スペースで一致しない if "%VAR%"=="hello" echo 一致 ← 表示されない! :: 対策: set の代入をダブルクォートで囲む set "VAR=hello" if "%VAR%"=="hello" echo 一致 ← 正常に表示される
set VAR=hello ではなく set "VAR=hello"(等号の左右を含めてクォート)で書くと、行末のスペースが変数に含まれません。この書き方を習慣にするだけで比較失敗バグの大半を防げます。変数末尾の空白問題の詳細は 変数の末尾に余計な空白が入るときの原因と対策、変数展開トラブル全般は 変数展開が思った通りに動かない原因と修正方法 を参照してください。
8. PowerShell を使った高度な文字列比較
バッチの findstr で対応できない複雑なパターンマッチにはPowerShell を呼び出します。
8-1. 正規表現で完全一致・部分一致
@echo off
setlocal
set STR=user@example.com
:: PowerShell の -match で正規表現マッチ
powershell -Command "if ('%STR%' -match '^[\w.-]+@[\w.-]+\.\w{2,}$') { exit 0 } else { exit 1 }"
if %errorlevel% equ 0 (
echo 有効なメールアドレス形式です
) else (
echo メールアドレス形式が不正です
)
8-2. 大文字小文字を無視した部分一致(-ilike)
@echo off
setlocal
set STR=C:\Program Files (x86)\MyApp
:: -ilike はワイルドカード・大文字小文字無視
powershell -Command "if ('%STR%' -ilike '*program files*') { exit 0 } else { exit 1 }"
if %errorlevel% equ 0 echo "Program Files" が含まれています
:: -icontains は配列内一致
set VAL=CSV
powershell -Command "if (@('csv','tsv','txt') -icontains '%VAL%') { exit 0 } else { exit 1 }"
if %errorlevel% equ 0 echo %VAL% は対応形式のひとつです
| PowerShell 演算子 | 意味 | バッチ代替 |
|---|---|---|
-eq |
完全一致(大文字小文字無視) | if /i "A"=="B" |
-ceq |
完全一致(大文字小文字区別) | if "A"=="B" |
-like |
ワイルドカード一致 | findstr で代替 |
-match |
正規表現マッチ | findstr /r(機能限定) |
-contains |
配列に含まれるか | フラグ変数+複数 if |
-startswith |
前方一致 | %VAR:~0,n% 切り出し比較 |
-endswith |
後方一致 | %VAR:~-n% 末尾切り出し比較 |
9. 実践例3本
実践例1:引数のバリデーション(必須チェック・値域チェック)
@echo off
setlocal
:: 使い方: deploy.bat <env> <version>
:: env: development | staging | production
:: version: v数字.数字.数字 の形式
set ENV=%~1
set VERSION=%~2
:: 必須チェック
if not defined ENV (
echo [ERROR] 環境名を指定してください
goto :usage
)
if "%VERSION%"=="" (
echo [ERROR] バージョンを指定してください
goto :usage
)
:: 環境名チェック(allowed values)
set VALID_ENV=0
if /i "%ENV%"=="development" set VALID_ENV=1
if /i "%ENV%"=="staging" set VALID_ENV=1
if /i "%ENV%"=="production" set VALID_ENV=1
if "%VALID_ENV%"=="0" (
echo [ERROR] 不明な環境名: %ENV%
echo 有効な値: development / staging / production
exit /b 1
)
:: バージョン形式チェック(v1.2.3 形式)
echo %VERSION% | findstr /r /c:"^v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$" >nul
if %errorlevel% neq 0 (
echo [ERROR] バージョン形式が不正: %VERSION%
echo 正しい形式: v1.0.0
exit /b 1
)
echo [OK] 環境: %ENV% バージョン: %VERSION%
echo デプロイを開始します...
goto :eof
:usage
echo 使い方: %~nx0 ^<env^> ^<version^>
echo 例: %~nx0 staging v1.2.3
exit /b 1
実践例2:環境変数から設定を読み込んで整合性チェック
@echo off
setlocal enabledelayedexpansion
:: 必須環境変数のチェック
:: ※ if not defined %%V は動かない(defined はリテラル変数名を期待する)
:: → call サブルーチンで間接参照する方法を使う
set REQUIRED_VARS=DB_HOST DB_PORT DB_NAME APP_ENV
set MISSING=0
for %%V in (%REQUIRED_VARS%) do (
call :check_defined %%V
)
if "%MISSING%"=="1" (
echo 上記の環境変数を設定してから再実行してください
exit /b 1
)
:: APP_ENV の値域チェック
set VALID=0
if /i "%APP_ENV%"=="production" set VALID=1
if /i "%APP_ENV%"=="staging" set VALID=1
if /i "%APP_ENV%"=="development" set VALID=1
if "%VALID%"=="0" (
echo [ERROR] APP_ENV の値が不正: %APP_ENV%
exit /b 1
)
:: DB_PORT が数値かチェック
echo %DB_PORT% | findstr /r /c:"^[0-9][0-9]*$" >nul
if %errorlevel% neq 0 (
echo [ERROR] DB_PORT は数値で指定してください: %DB_PORT%
exit /b 1
)
echo [OK] すべての環境変数が正常に設定されています
echo APP_ENV=%APP_ENV% / DB_HOST=%DB_HOST%:%DB_PORT% / DB=%DB_NAME%
goto :eof
:: サブルーチン: 変数名を引数として受け取り未定義チェック
:check_defined
if not defined %~1 (
echo [ERROR] 環境変数 %~1 が設定されていません
set MISSING=1
)
exit /b 0
実践例3:ファイル名のパターンで処理を振り分ける
@echo off
setlocal enabledelayedexpansion
:: input フォルダのファイルをパターンで仕分け
set INDIR=C:\input
set ERR_COUNT=0
for %%F in ("%INDIR%\*.*") do (
set FNAME=%%~nxF
set EXT=%%~xF
:: 拡張子で振り分け
if /i "!EXT!"==".csv" (
move "%%F" "C:\output\csv\" >nul
echo [CSV] !FNAME!
) else if /i "!EXT!"==".xml" (
move "%%F" "C:\output\xml\" >nul
echo [XML] !FNAME!
) else if /i "!EXT!"==".log" (
:: "error_" で始まるログは別扱い
echo !FNAME! | findstr /r /c:"^error_" >nul
if !errorlevel! equ 0 (
move "%%F" "C:\output\error_logs\" >nul
echo [ERR_LOG] !FNAME!
) else (
move "%%F" "C:\output\logs\" >nul
echo [LOG] !FNAME!
)
) else (
echo [SKIP] !FNAME! (未対応の拡張子)
set /a ERR_COUNT+=1
)
)
echo 完了 (未対応ファイル: %ERR_COUNT% 件)
文字列の切り出し・抽出については 文字列を切り出して抽出する方法、文字列の置換については 文字列置換する方法完全ガイド も参照してください。
10. まとめ:比較パターン別チートシート
| やりたいこと | 方法 | ポイント |
|---|---|---|
| 完全一致 | if "%A%"=="%B%" |
ダブルクォート必須 |
| 大文字小文字無視の完全一致 | if /i "%A%"=="%B%" |
/i を追加するだけ |
| 否定(一致しない) | if not "%A%"=="%B%" |
not を if の直後に置く |
| 空文字チェック | if "%VAR%"=="" |
ダブルクォートで囲む |
| 未定義チェック | if not defined VAR |
% 不要 |
| 部分一致 | echo %S% | findstr /c:"キー" |
>nul で出力を捨てる |
| 前方一致 | if "%VAR:~0,n%"=="..." |
文字数固定なら切り出し比較が速い |
| 後方一致 | if "%VAR:~-n%"=="..." |
末尾 n 文字を切り出して比較 |
| 拡張子チェック | if /i "%%~xF"==".csv" |
for の %%~xF が確実 |
| 正規表現マッチ | echo %S% | findstr /r /c:"正規表現" |
Windows findstr の正規表現は限定的 |
| 高度な正規表現 | PowerShell -match |
PCRE相当の正規表現が使える |
| 複数値のいずれか一致(OR) | フラグ変数+複数 if |
findstr の複数 /c: でも代替可 |
FAQ
Qif %VAR%==%VAR2% と if “%VAR%”==”%VAR2%” の違いは何ですか?
Aクォートなしの if %VAR%==%VAR2% は変数が空や未定義のとき if == となり構文エラーになります。また値にスペースが含まれると if hello world==hello のように解釈されてエラーになります。必ずダブルクォートで囲む if "%VAR%"=="%VAR2%" を使ってください。
Q/i オプションで日本語の大文字小文字も無視できますか?
Aif /i は ASCII 範囲(A-Z)の大文字小文字のみ無視します。全角カタカナのひらがな/カタカナ変換などの日本語正規化は対応していません。日本語の表記ゆれを吸収したい場合は PowerShell の -eq(カルチャ依存)や専用の変換処理を実装してください。
Qfor ループ内で if 比較の結果が変です。
Aよくある原因は遅延展開の問題です。for ループ内で変更した変数を %VAR% で参照すると、ループ開始時点の値が展開されます。setlocal enabledelayedexpansion を使い、ループ内では !VAR! で参照してください。
Qfindstr で日本語文字列を検索すると文字化けして正しく動作しません。
Afindstr は日本語(マルチバイト文字)の扱いが不安定です。バッチファイルの文字コード(Shift_JIS)とファイルの文字コードが一致していることを確認し、それでも動作しない場合は PowerShell の -match や -contains を使ってください。
Q変数の値を小文字に変換してから比較したいです。
Aバッチ単体では文字列の大文字小文字変換はできません。if /i(比較時に無視)で代替するか、PowerShell で変換します:for /f %%L in ('powershell -Command "'%VAR%'.ToLower()"') do set LOWER=%%L。ただし多くの場合は if /i で十分です。
Q文字列の長さを取得して比較したいです。
A純バッチでは for /l ループで文字を1つずつカウントする方法か、PowerShell で取得します:for /f %%N in ('powershell -Command "'%VAR%'.Length"') do set LEN=%%N。長さを取得したら if %LEN% gtr 8 のように数値比較で使えます。
