バッチファイルには && 演算子がなく、AND条件は IF を入れ子にする ことで実現します。シンプルに見えますが「引用符の有無」「遅延展開が必要なケース」「NOT との組み合わせ」など、落とし穴が多い文法です。
この記事では AND条件の全パターン を体系的に解説し、コピーしてすぐ使える実践例を3本紹介します。
- IF 入れ子でAND条件を作る基本構文
- 数値・文字列・IF EXIST・ERRORLEVEL それぞれのAND結合
- NOT条件のAND(ド・モルガンの法則)
- IF DEFINED を使った変数定義チェックのAND
- 遅延展開(!変数!)との組み合わせ
- 3つ以上の条件を連結するときの注意点
- 落とし穴5選・実践例3本・FAQ6問
1. AND条件の基本:IF を入れ子にする
バッチファイルに && 演算子はありません。AND条件は IF を連続して書く(入れ子にする)ことで実現します。
1-1. 基本構文
@echo off
:: IF 入れ子 = AND 条件
if %VAR1%==A if %VAR2%==B (
echo 両方の条件が成立しました
)
内側の IF が評価されるのは、外側の IF が成立した場合だけです。つまり VAR1==A かつ VAR2==B のときだけブロックが実行されます。
1-2. 変数を引用符で保護する
変数が空になる可能性がある場合は引用符で囲みます。引用符なしで空変数を展開すると構文エラーになります。
:: 変数が空のときに備えて引用符で囲む(推奨)
if "%VAR1%"=="A" if "%VAR2%"=="B" (
echo OK: 両方の条件が成立しました
)
:: 数値比較は引用符不要(むしろ付けると文字列比較になる)
if %NUM1% EQU 5 if %NUM2% GTR 10 (
echo NUM1=5 かつ NUM2>10
)
文字列比較には引用符を付け、数値比較(EQU/GTR/LSS など)には付けないのが基本ルールです。文字列の比較方法・数値の比較方法もあわせて確認してください。
2. 2条件・3条件・4条件のAND
2-1. 2つの条件をANDで結合
@echo off
set "STATUS=active"
set "ROLE=admin"
if "%STATUS%"=="active" if "%ROLE%"=="admin" (
echo [OK] アクティブな管理者です
) else (
echo 条件を満たしません
)
注意: else は 最後の IF に対応します。「STATUS==active が偽のとき」ではなく「ROLE==admin が偽のとき」に else が実行されます。AND全体の偽に対応する else が必要な場合はフラグ変数を使います(→ 5節)。
2-2. 3つの条件をANDで結合
@echo off
set "OS=Windows"
set "VER=10"
set "ARCH=64"
:: IF を3重に入れ子にする
if "%OS%"=="Windows" if "%VER%"=="10" if "%ARCH%"=="64" (
echo [OK] Windows 10 64bit 環境です
)
2-3. 4つ以上の条件(可読性の工夫)
条件が4つ以上になると入れ子が深くなり読みにくくなります。各条件を事前にフラグで評価してから最終判定する方法が読みやすいです。
@echo off
set "C1=" & set "C2=" & set "C3=" & set "C4="
:: 各条件を個別にフラグ化
if "%ENV%"=="prod" set "C1=1"
if %SIZE% GEQ 100 set "C2=1"
if exist "%CONF_FILE%" set "C3=1"
if "%STATUS%"=="OK" set "C4=1"
:: すべてのフラグが立っていれば AND 成立
if defined C1 if defined C2 if defined C3 if defined C4 (
echo [OK] すべての条件が成立しました
) else (
echo [NG] 条件を満たしません
)
3. 数値比較のAND
数値比較の AND は EQU / NEQ / GTR / GEQ / LSS / LEQ の組み合わせで記述します。詳細は 数値比較の完全ガイド を参照してください。
3-1. 範囲チェック(下限 AND 上限)
@echo off
set /p SCORE=スコアを入力してください:
:: 60 以上 かつ 100 以下 = 合格
if %SCORE% GEQ 60 if %SCORE% LEQ 100 (
echo [合格] スコア: %SCORE%
) else (
echo [不合格] スコア: %SCORE%
)
3-2. 複数の数値条件を組み合わせる
@echo off
set "HOUR=14"
set "MIN=30"
:: 14:00〜14:59 の間かチェック
if %HOUR% EQU 14 if %MIN% GEQ 0 if %MIN% LEQ 59 (
echo 現在は14時台です(%HOUR%:%MIN%)
)
:: ファイルサイズが 100KB 以上 かつ 10MB 以下かチェック
for %%F in ("C:\work\data.csv") do set "SZ=%%~zF"
if %SZ% GEQ 102400 if %SZ% LEQ 10485760 (
echo ファイルサイズが適正範囲内です(%SZ% bytes)
)
4. 文字列比較のAND
文字列比較は大文字/小文字を区別します(/i で無視できます)。詳細は 文字列比較の方法 を参照してください。
4-1. 複数の文字列を同時チェック
@echo off
set "TYPE=csv"
set "MODE=batch"
:: 大文字小文字を区別せず比較(/i)
if /i "%TYPE%"=="csv" if /i "%MODE%"=="batch" (
echo CSV ファイルをバッチモードで処理します
)
4-2. 空文字チェックとの組み合わせ
@echo off
set "NAME=%~1"
set "DEPT=%~2"
:: 両方の引数が空でないことを確認
if not "%NAME%"=="" if not "%DEPT%"=="" (
echo 担当: %NAME% / 部門: %DEPT%
) else (
echo エラー: 名前と部門の両方を指定してください
exit /b 1
)
5. IF DEFINED を使ったAND(変数の定義チェック)
if defined 変数名 は変数が定義されているかどうかを確認します。空文字チェックよりシンプルに書けるため積極的に使いましょう。
@echo off
:: 2つの変数が両方とも定義されていることをチェック
if defined INPUT_FILE if defined OUTPUT_DIR (
echo 処理を開始します
echo 入力: %INPUT_FILE%
echo 出力先: %OUTPUT_DIR%
) else (
echo エラー: INPUT_FILE と OUTPUT_DIR を設定してください
exit /b 1
)
:: NOT DEFINED との組み合わせ
:: 変数A が未定義 かつ 変数B も未定義(= まったく初期化されていない状態)
if not defined CONFIG if not defined PROFILE (
echo 初回起動: デフォルト設定を適用します
)
6. IF EXIST を使ったAND(ファイル・フォルダの存在チェック)
ファイルとフォルダの両方が存在する場合にのみ処理を進めたいケースに使います。詳細は IF EXISTの使い方 を参照してください。
@echo off
set "DATA_FILE=C:\work\input.csv"
set "OUT_DIR=C:\work\output"
:: ファイルが存在 かつ 出力フォルダが存在する場合にのみ処理
if exist "%DATA_FILE%" if exist "%OUT_DIR%\" (
echo [OK] 入力ファイルと出力フォルダを確認しました
copy "%DATA_FILE%" "%OUT_DIR%\" >nul
echo コピー完了
) else (
echo [ERROR] 入力ファイルまたは出力フォルダが存在しません
if not exist "%DATA_FILE%" echo - %DATA_FILE% が見つかりません
if not exist "%OUT_DIR%\" echo - %OUT_DIR% が見つかりません
exit /b 1
)
6-2. NOT EXIST との組み合わせ
@echo off
:: ロックファイルが存在しない かつ 入力ファイルが存在する = 処理を実行
set "LOCK_FILE=C:\work\process.lock"
set "INPUT=C:\work\data.csv"
if not exist "%LOCK_FILE%" if exist "%INPUT%" (
echo [OK] 処理を開始します
echo running > "%LOCK_FILE%"
:: 処理
del "%LOCK_FILE%"
) else (
if exist "%LOCK_FILE%" echo [SKIP] 別プロセスが実行中です
if not exist "%INPUT%" echo [ERROR] 入力ファイルがありません
)
7. ERRORLEVELのAND
複数コマンドが連続して成功したかどうかをAND判定するパターンです。ERRORLEVELを使ったエラーハンドリングもあわせて参照してください。
@echo off
setlocal
:: コマンド1 を実行して ERRORLEVEL を保存
xcopy /e /y "C:\src" "C:\dst\" >nul 2>&1
set "ERR1=%ERRORLEVEL%"
:: コマンド2 を実行して ERRORLEVEL を保存
robocopy "C:\work" "D:\backup" /mir >nul 2>&1
set "ERR2=%ERRORLEVEL%"
:: 両方が成功(ERRORLEVEL == 0)なら AND 成立
if %ERR1% EQU 0 if %ERR2% LSS 8 (
echo [OK] すべてのコピーが成功しました
) else (
echo [ERROR] コピーに失敗しました
if not %ERR1% EQU 0 echo - xcopy ERRORLEVEL: %ERR1%
if %ERR2% GEQ 8 echo - robocopy ERRORLEVEL: %ERR2%
exit /b 1
)
注意: robocopy は成功時でも ERRORLEVEL が 1〜7 になります(コピー件数によって変化)。「エラーなし」の判定は LSS 8 を使います。
8. 遅延展開との組み合わせ
FOR ループや IF ブロックの内側で変数を更新して AND 判定するには遅延展開(!変数!)が必要です。詳細は setlocal enabledelayedexpansion 完全ガイド と 変数展開が動かない原因と修正方法 を参照してください。
@echo off
setlocal enabledelayedexpansion
set "FOUND_CSV="
set "FOUND_LOG="
:: ループ内でフラグを更新
for %%F in ("C:\work\*") do (
if /i "%%~xF"==".csv" set "FOUND_CSV=1"
if /i "%%~xF"==".log" set "FOUND_LOG=1"
)
:: ループ後に AND 判定(!変数! で遅延展開)
if defined FOUND_CSV if defined FOUND_LOG (
echo [OK] csv と log の両方が存在します
) else (
echo [NG] 必要なファイルが揃っていません
if not defined FOUND_CSV echo - .csv が見つかりません
if not defined FOUND_LOG echo - .log が見つかりません
)
8-2. ループ内の AND 判定(即時評価)
@echo off
setlocal enabledelayedexpansion
set "LIMIT=100"
:: ループ内で更新した変数を !変数! で AND 判定
for /l %%i in (1,1,10) do (
set /a VAL=%%i * 15
:: VAL が 50 以上 かつ 100 以下かを遅延展開で判定
if !VAL! GEQ 50 if !VAL! LEQ !LIMIT! (
echo %%i: !VAL! は範囲内です
)
)
9. NOT条件のANDとド・モルガンの法則
「AでもなくBでもない」という条件は、ド・モルガンの法則(NOT(A OR B) = NOT A AND NOT B)を使って IF NOT の入れ子で書けます。
@echo off
set "TYPE=%~1"
:: "csv" でも "tsv" でもない場合にエラー
:: ド・モルガン: NOT(csv OR tsv) = NOT csv AND NOT tsv
if not "%TYPE%"=="csv" if not "%TYPE%"=="tsv" (
echo [ERROR] タイプは csv または tsv を指定してください
exit /b 1
)
echo [OK] タイプ: %TYPE%
:: 同等の判定(可読性比較)
:: IF を使ったフラグ方式(4条件以上に向く)
set "VALID="
if "%TYPE%"=="csv" set "VALID=1"
if "%TYPE%"=="tsv" set "VALID=1"
if "%TYPE%"=="json" set "VALID=1"
if not defined VALID (
echo [ERROR] 無効なタイプ: %TYPE%
exit /b 1
)
10. AND 全体の ELSE をうまく書く方法
IF 入れ子で ELSE を使うと、最後の IF の ELSE として解釈されるため、AND 全体の偽を表す ELSE にはなりません。フラグ変数を使って AND 全体の結果を明示的に管理するのが確実な方法です。
:: NG: else が最後の IF(if "%B%"=="2")にしか対応しない
if "%A%"=="1" if "%B%"=="2" (
echo 両方成立
) else (
echo どちらかが不成立(※ A==1 かつ B!=2 の場合のみ実行!A!=1 では実行されない)
)
:: OK: フラグ変数で AND 全体の真偽を管理する
@echo off
set "AND_OK="
if "%A%"=="1" if "%B%"=="2" set "AND_OK=1"
if defined AND_OK (
echo [OK] 両方の条件が成立しました
) else (
echo [NG] いずれかの条件が不成立です
)
このパターンは条件が多くなるほど読みやすくなるため積極的に使いましょう。条件分岐全般については バッチファイルで条件分岐する方法完全ガイド も参照してください。
11. 落とし穴5選と対策
落とし穴1:else が最後の IF にしか対応しない
:: 罠: if "%A%"=="1" が偽のとき else は実行されない
if "%A%"=="1" if "%B%"=="2" (
echo 成立
) else (
:: ここは「A==1 かつ B!=2」のときしか実行されない
echo 不成立(と思って書いたが実は不完全)
)
:: 対策: AND 全体の判定にフラグ変数を使う(→ 10節参照)
落とし穴2:変数が空のとき引用符なしで比較すると構文エラー
:: NG: VAR が空だと "if ==value" になって構文エラー
if %VAR%==value if %VAR2%==B echo OK
:: OK: 引用符で保護すれば空変数でも安全
if "%VAR%"=="value" if "%VAR2%"=="B" echo OK
:: または IF DEFINED で先に存在確認
if defined VAR if defined VAR2 (
if "%VAR%"=="value" if "%VAR2%"=="B" echo OK
)
変数展開の問題については 変数展開が動かない原因と修正方法 も参照してください。
落とし穴3:ループ内で更新した変数を % で参照すると古い値になる
:: NG: ループ内で set した変数を %変数% で読むと更新前の値
for %%i in (1 2 3) do (
set /a COUNT+=1
if %COUNT% GEQ 2 echo 2回以上 ← COUNT が 0 のまま判定される
)
:: OK: setlocal enabledelayedexpansion + !変数! を使う
setlocal enabledelayedexpansion
for %%i in (1 2 3) do (
set /a COUNT+=1
if !COUNT! GEQ 2 echo 2回以上
)
落とし穴4:特殊文字(& | < >)を含む値の比較が失敗する
:: NG: 特殊文字を含む値は引用符で囲んでも ^エスケープが必要なケースがある set "VAL=hello&world" if "%VAL%"=="hello&world" echo OK :: & がコマンド区切りとして解釈される :: OK: IF DEFINED + 部分一致で回避するか、特殊文字を含む変数は処理設計を見直す :: 詳細は「特殊文字を含むとエラーになるときの回避方法」参照
特殊文字を含むとエラーになるときの回避方法 も参照してください。
落とし穴5:数値比較に引用符を付けると文字列比較になり誤動作する
:: NG: 引用符付きの数値比較は文字列比較(辞書順)になる :: "9" > "10" は辞書順で真になってしまう if "%NUM%" GEQ "10" echo 10以上 :: ← NG(文字列として比較される) :: OK: 数値比較には引用符を付けない if %NUM% GEQ 10 echo 10以上
12. 実践例3本
実践例1:バックアップ実行前の多重条件チェック
入力フォルダの存在・出力フォルダの存在・ロックファイルの不在・フリーディスク容量(外部コマンド取得)を AND で確認してからバックアップを実行します。
@echo off
setlocal enabledelayedexpansion
set "SRC=C:\work\data"
set "DST=D:\backup\data"
set "LOCK=C:\work\backup.lock"
:: フリーディスク容量を取得(MB単位)
:: wmic /value 形式の出力は "FreeSpace=1234567" なので tokens=2 delims== で数値部分を取得
for /f "tokens=2 delims==" %%A in ('wmic logicaldisk where "DeviceID='D:'" get FreeSpace /value ^| findstr /i "FreeSpace"') do (
set /a FREE_MB=%%A / 1048576
)
:: AND 全体の判定をフラグで管理
set "READY="
if exist "%SRC%\" set "R1=1"
if exist "%DST%\" set "R2=1"
if not exist "%LOCK%" set "R3=1"
if !FREE_MB! GEQ 500 set "R4=1"
if defined R1 if defined R2 if defined R3 if defined R4 set "READY=1"
if not defined READY (
echo [ERROR] バックアップを開始できません
if not defined R1 echo - コピー元が存在しません: %SRC%
if not defined R2 echo - コピー先が存在しません: %DST%
if not defined R3 echo - バックアップが既に実行中です(ロックファイルあり)
if not defined R4 echo - Dドライブの空き容量が不足しています(!FREE_MB! MB)
exit /b 1
)
echo [OK] 全条件を満たしました。バックアップを開始します...
echo running > "%LOCK%"
robocopy "%SRC%" "%DST%" /mir /r:3 /w:5
del "%LOCK%"
echo [完了] バックアップが完了しました
実践例2:デプロイ前の環境・引数・ファイル一括バリデーション
@echo off
setlocal enabledelayedexpansion
:: 引数チェック
set "TARGET=%~1"
set "ENV=%~2"
set "OK="
:: 1. 引数が両方指定されているか
if not "%TARGET%"=="" if not "%ENV%"=="" set "OK=1"
if not defined OK (
echo 使い方: %~nx0 ^<デプロイ先フォルダ^> ^<環境名: dev^|stg^|prod^>
exit /b 1
)
:: 2. 環境名が有効か
set "ENV_OK="
if /i "%ENV%"=="dev" set "ENV_OK=1"
if /i "%ENV%"=="stg" set "ENV_OK=1"
if /i "%ENV%"=="prod" set "ENV_OK=1"
if not defined ENV_OK (
echo [ERROR] 環境名は dev / stg / prod のいずれかを指定してください
exit /b 1
)
:: 3. デプロイ先と設定ファイルの存在確認
set "CONF=config_%ENV%.ini"
set "FINAL="
if exist "%TARGET%\" set "T1=1"
if exist "%CONF%" set "T2=1"
if defined T1 if defined T2 set "FINAL=1"
if not defined FINAL (
echo [ERROR] デプロイ準備が整っていません
if not defined T1 echo - デプロイ先フォルダが存在しません: %TARGET%
if not defined T2 echo - 設定ファイルが存在しません: %CONF%
exit /b 1
)
echo [OK] バリデーション通過。%ENV% 環境にデプロイします...
xcopy /e /y ".\" "%TARGET%\" >nul
echo [完了]
実践例3:ログ監視 AND 条件による自動アラート
ログファイルが存在し、かつ特定キーワードを含み、かつ最終更新から30分以内の場合にアラートを出すスクリプトです。FINDSTRコマンドの使い方 も参照してください。
@echo off
setlocal enabledelayedexpansion
set "LOGFILE=C:\work\app.log"
set "KEYWORD=ERROR"
:: 条件1: ログファイルが存在する
if not exist "%LOGFILE%" (
echo [SKIP] ログファイルが存在しません
exit /b 0
)
:: 条件2: ログにキーワードが含まれる
findstr /i "%KEYWORD%" "%LOGFILE%" >nul 2>&1
set "HAS_KEYWORD=%ERRORLEVEL%"
:: 条件3: ログの更新が30分以内(ファイルのタイムスタンプを確認)
set "RECENT="
for /f "tokens=1,2" %%A in ('wmic datafile where "name='C:\\work\\app.log'" get LastModified /value ^| findstr LastModified') do (
:: 現在時刻と比較(簡易版: forfiles で30分以内のファイルを検索)
forfiles /p "C:\work" /m "app.log" /d +0 >nul 2>&1
if !ERRORLEVEL! EQU 0 set "RECENT=1"
)
:: AND 判定: キーワードあり かつ 最近更新されたファイル
if %HAS_KEYWORD% EQU 0 if defined RECENT (
echo [ALERT] %date% %time% - %LOGFILE% に %KEYWORD% が検出されました!
echo アラート送信処理をここに記述...
) else (
echo [OK] アラート条件を満たしません
)
13. まとめ:AND条件パターン早見表
| パターン | 構文 | 用途・注意点 |
|---|---|---|
| 文字列AND | if "%A%"=="x" if "%B%"=="y" |
引用符で空変数を保護 |
| 数値AND | if %N% GEQ 1 if %N% LEQ 10 |
数値比較は引用符不要 |
| EXIST AND | if exist "f1" if exist "f2" |
フォルダは末尾に \ を付ける |
| DEFINED AND | if defined V1 if defined V2 |
変数定義チェックに最適 |
| NOT AND | if not "%" == "x" if not "%" == "y" |
ド・モルガン活用 |
| ERRORLEVEL AND | set ERR=%ERRORLEVEL% → if %ERR% EQU 0 if … |
コマンド後すぐ保存する |
| フラグ方式 | 各条件を SET → if defined F1 if defined F2 |
4条件以上・AND全体のelseに使う |
| 遅延展開 | if !VAR! GEQ 0 if !VAR! LEQ 100 |
ループ・IF内の変数更新後に使用 |
FAQ
&& 演算子は使えますか?&& はコマンドの連結(前のコマンドが成功した場合に次を実行)には使えますが、if 文の条件式では使えません。IF 文のAND条件は IF の入れ子(if 条件1 if 条件2)で実現します。else は最後の IF にしか対応しません。AND 全体の偽に対応する else が必要な場合はフラグ変数を使って AND 結果を一時保存し、そのフラグで if/else を書いてください(→ 10節)。if 条件1 if 条件2 if 条件3 ( … ) と連続して書けます。ただし4条件以上になると可読性が下がるため、各条件をフラグ変数に評価してから最終判定するフラグ方式を推奨します(→ 2-3節)。%変数% の展開がブロック進入時に固定されます。ループ内で更新した変数を参照するには setlocal enabledelayedexpansion を宣言して !変数! で参照してください(→ 8節)。set "FLAG=1" するパターンで実現します。/i を付けてください。if /i "%A%"=="csv" if /i "%B%"=="batch" ( … ) のように、入れ子のすべての IF に /i を明示します。
