【bat】バッチファイルで文字列を比較する方法完全ガイド|完全一致・大文字小文字無視・部分一致・空文字・未定義チェック・正規表現まで徹底解説

バッチファイルの文字列比較は「完全一致の 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
)
/i はすべての文字列比較に使えるわけではない
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
defined と空文字は別物
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_" で始まっています(切り出し比較)
)
文字列切り出し比較は高速・findstr 不要
%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 == は文字列比較!数値の大小比較には使えない
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 は必ず set “VAR=値” の形式で書く
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%" notif の直後に置く
空文字チェック 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 のように数値比較で使えます。