バッチファイルに引数を渡すことで、同じスクリプトを様々な入力に対応させられます。ファイルパスを渡す、動作モードを切り替える、複数ファイルをまとめて処理するなど、引数の活用で自動化の幅が大きく広がります。
この記事では %1〜%9の基本から、%~修飾子・shift・名前付き引数・フラグ引数・バリデーション・デフォルト値設定 まで、体系的に解説します。
- %0〜%9・%* による引数の受け取り方
- %~ 修飾子によるパス・ファイル名の展開
- shift で引数をスライドして可変長引数を処理する方法
- 引数のバリデーション(存在確認・型チェック)
- デフォルト値の設定パターン
- 名前付き引数(/key:value)とフラグ引数(/flag)の実装
- サブルーチンへの引数渡しと戻り値の受け取り
- 落とし穴5選・実践例3本・FAQ6問
1. 引数の基本:%0〜%9 と %*
バッチファイルを script.bat arg1 arg2 arg3 のように実行すると、各引数が %1・%2・%3 に格納されます。%0 はバッチファイル自身のパスです。
@echo off setlocal echo バッチ自身のパス: %0 echo 第1引数: %1 echo 第2引数: %2 echo 第3引数: %3 echo すべての引数: %*
実行例:
script.bat apple banana cherry 出力: バッチ自身のパス: script.bat 第1引数: apple 第2引数: banana 第3引数: cherry すべての引数: apple banana cherry
| 変数 | 内容 |
|---|---|
%0 |
バッチファイル自身のパス(実行方法により変わる) |
%1〜%9 |
1番目〜9番目の引数 |
%* |
渡されたすべての引数をまとめた文字列 |
2. %~ 修飾子:引数からパスやファイル名を展開する
引数に渡されたファイルパスから、ドライブ名・フォルダ・ファイル名・拡張子などを個別に取り出せます。ファイルパス操作の詳細は バッチファイルのパスやファイル名を取得する方法も参照してください。
主要な %~ 修飾子一覧
| 修飾子 | 展開される内容 | 例(引数: C:\work\data.csv) |
|---|---|---|
%~1 |
引用符を除いた引数の値 | C:\work\data.csv |
%~f1 |
絶対パスに展開 | C:\work\data.csv |
%~d1 |
ドライブ文字のみ | C: |
%~p1 |
パス部分のみ(末尾 \ 付き) | \work\ |
%~n1 |
拡張子なしのファイル名 | data |
%~x1 |
拡張子のみ(ドット付き) | .csv |
%~dp1 |
ドライブ + パス | C:\work\ |
%~nx1 |
ファイル名 + 拡張子 | data.csv |
%~z1 |
ファイルサイズ(バイト) | 1024 |
%~t1 |
ファイルの更新日時 | 2025/01/01 12:00 |
実用例:渡されたファイルをバックアップ
@echo off
setlocal
:: 引数チェック
if "%~1"=="" (
echo 使い方: %~nx0 ファイルパス
exit /b 1
)
:: パスを分解
set "SRC=%~f1"
set "DIR=%~dp1"
set "NAME=%~n1"
set "EXT=%~x1"
:: バックアップ先ファイル名を生成(元のファイル名_backup.拡張子)
set "BACKUP=%DIR%%NAME%_backup%EXT%"
if not exist "%SRC%" (
echo [ERROR] ファイルが見つかりません: %SRC%
exit /b 1
)
copy "%SRC%" "%BACKUP%" >nul
echo [OK] バックアップ作成: %BACKUP%
3. shift でスライドして可変長引数を処理する
shift を使うと引数を1つ左にずらせます。%2 が %1 に、%3 が %2 になります。これで9個以上の引数や、個数が不定の引数をループ処理できます。
shift の基本動作
@echo off setlocal echo 実行前: %1 %2 %3 shift echo shift後: %1 %2 %3 :: 実行: script.bat A B C D :: 実行前: A B C :: shift後: B C D
すべての引数をループ処理する
@echo off setlocal enabledelayedexpansion set "CNT=0" :loop if "%~1"=="" goto :done set /a CNT+=1 echo 引数 !CNT!: %1 shift goto :loop :done echo 引数の合計: %CNT% 個
実行例: script.bat file1.txt file2.txt file3.txt
先頭引数を変数に保存してから残りをシフトループで処理する
@echo off setlocal enabledelayedexpansion :: 第1引数(コマンド名)を変数に保存してから shift :: → 以降のループで %1 は元の %2・%3... を順に指すようになる set "CMD=%~1" shift echo コマンド: %CMD% :file_loop if "%~1"=="" goto :file_done echo 対象ファイル: %1 shift goto :file_loop :file_done :: 実行: script.bat backup a.txt b.txt c.txt :: → コマンド: backup, 対象: a.txt b.txt c.txt
4. 引数のバリデーション
引数の有無・内容・ファイル存在などを実行前に確認することで、意図しない処理を防げます。
4-1. 必須引数の確認
@echo off
setlocal
:: 引数が指定されているか確認
if "%~1"=="" (
echo [ERROR] 引数が不足しています
echo 使い方: %~nx0 入力ファイル 出力フォルダ
echo 例: %~nx0 C:\data\input.csv C:\output
exit /b 1
)
if "%~2"=="" (
echo [ERROR] 出力フォルダを指定してください
exit /b 1
)
set "INPUT=%~1"
set "OUTDIR=%~2"
:: ファイルの存在確認
if not exist "%INPUT%" (
echo [ERROR] 入力ファイルが見つかりません: %INPUT%
exit /b 1
)
echo [OK] 入力: %INPUT% / 出力先: %OUTDIR%
4-2. 引数の型チェック(数値かどうか)
@echo off
setlocal
:: 数値チェック: set /a で変換を試み、エラーなら非数値
set "NUM=%~1"
set /a TEST=%NUM% 2>nul
if "%TEST%"=="%NUM%" (
echo %NUM% は数値です
) else (
echo [ERROR] %NUM% は数値ではありません
exit /b 1
)
4-3. 引数の選択肢チェック
@echo off setlocal set "ENV=%~1" :: 許可された値かを確認 if /i "%ENV%"=="production" goto :ok if /i "%ENV%"=="staging" goto :ok if /i "%ENV%"=="dev" goto :ok echo [ERROR] 環境名が不正: %ENV% echo production / staging / dev のいずれかを指定してください exit /b 1 :ok echo 環境: %ENV%
5. デフォルト値の設定
引数が省略された場合にデフォルト値を使うパターンです。
@echo off
setlocal
:: 引数が空ならデフォルト値を設定
if "%~1"=="" (
set "INPUT=C:\work\default_input.csv"
) else (
set "INPUT=%~1"
)
if "%~2"=="" (
set "OUTPUT=C:\work\output"
) else (
set "OUTPUT=%~2"
)
echo 入力: %INPUT%
echo 出力: %OUTPUT%
より簡潔に書くには if not defined を利用する方法もあります。
@echo off setlocal :: 引数を変数にセット(未指定なら空のまま) set "INPUT=%~1" set "MODE=%~2" :: 空ならデフォルト値を上書き if not defined INPUT set "INPUT=C:\work\default.csv" if not defined MODE set "MODE=normal" echo 入力: %INPUT%, モード: %MODE%
6. 名前付き引数(/key:value 形式)
script.bat /input:data.csv /mode:fast のようなLinuxコマンドライン風の引数スタイルです。引数の順序を気にしなくて済むため、オプションが多いスクリプトに向いています。
@echo off
setlocal enabledelayedexpansion
:: デフォルト値
set "INPUT="
set "OUTPUT=C:\work\out"
set "MODE=normal"
:: 引数を順番にパース
:parse
if "%~1"=="" goto :end_parse
set "ARG=%~1"
:: /input:値 の形式で処理
if /i "!ARG:~0,7!"=="/input:" (
set "INPUT=!ARG:~7!"
shift & goto :parse
)
if /i "!ARG:~0,8!"=="/output:" (
set "OUTPUT=!ARG:~8!"
shift & goto :parse
)
if /i "!ARG:~0,6!"=="/mode:" (
set "MODE=!ARG:~6!"
shift & goto :parse
)
echo [WARN] 不明な引数: %1
shift
goto :parse
:end_parse
:: 必須引数チェック
if not defined INPUT (
echo [ERROR] /input:ファイルパス を指定してください
exit /b 1
)
echo 入力: %INPUT%
echo 出力: %OUTPUT%
echo モード: %MODE%
:: 実行例: script.bat /input:C:\data.csv /mode:fast /output:C:\out
7. フラグ引数(/flag スイッチ形式)
script.bat /verbose /dryrun のようなフラグ形式の引数パターンです。
@echo off setlocal enabledelayedexpansion :: フラグの初期値 set "VERBOSE=0" set "DRYRUN=0" set "FORCE=0" :parse if "%~1"=="" goto :end_parse if /i "%~1"=="/verbose" ( set "VERBOSE=1" & shift & goto :parse ) if /i "%~1"=="/dryrun" ( set "DRYRUN=1" & shift & goto :parse ) if /i "%~1"=="/force" ( set "FORCE=1" & shift & goto :parse ) if /i "%~1"=="/help" ( goto :usage ) :: 位置引数(フラグ以外)を受け取る場合 set "TARGET=%~1" shift goto :parse :end_parse if "%VERBOSE%"=="1" echo [詳細モード有効] if "%DRYRUN%"=="1" echo [ドライラン: 実際には変更しません] if "%FORCE%"=="1" echo [強制モード有効] echo 対象: %TARGET% exit /b 0 :usage echo 使い方: %~nx0 [オプション] 対象パス echo オプション: echo /verbose 詳細ログを表示 echo /dryrun 実行確認のみ(変更なし) echo /force 確認なし強制実行 echo /help このヘルプを表示 exit /b 0 :: 実行例: script.bat /verbose /dryrun C:\work
8. サブルーチンへの引数渡し
CALL でサブルーチンを呼び出す際も同様に引数を渡せます。サブルーチン完全ガイドも参照してください。
@echo off setlocal :: サブルーチンを引数付きで呼び出す call :greet "山田太郎" "おはよう" call :greet "鈴木花子" "こんにちは" exit /b 0 :greet :: %~1: 名前(引用符なしで受け取る) :: %~2: 挨拶 echo %~2、%~1さん! exit /b 0
サブルーチンからの戻り値(変数経由)
@echo off setlocal enabledelayedexpansion call :calc_sum 10 20 echo 合計: %RESULT% exit /b 0 :calc_sum set /a RESULT=%~1 + %~2 exit /b 0
9. 落とし穴5選と対策
落とし穴1:スペースを含む引数を引用符で囲まないとエラー
:: NG: パスにスペースがあると %1 が途中で切れる script.bat C:\my folder\data.csv :: → %1 = C:\my, %2 = folder\data.csv(2つに分かれる) :: OK: " " で囲んでから渡す script.bat "C:\my folder\data.csv" :: → %1 = "C:\my folder\data.csv" :: バッチ内では %~1 で引用符を取り除いて使う set "FILE=%~1" if exist "%FILE%" echo ファイルが見つかりました
パスにスペースが含まれているとエラーになるときの解決策も参照してください。
落とし穴2:%~1 と %1 の使い分けを間違える
:: %1 → 引用符を含んだままの値: "C:\work\file.csv" :: %~1 → 引用符を除いた値: C:\work\file.csv :: NG: %1 をそのまま if exist に渡すと ""-quoted になり二重引用符に if exist %1 echo OK :: OK: %~1 で引用符を除去し、if exist の中で改めて " で囲む if exist "%~1" echo OK
落とし穴3:shift した後は %0 の内容が変わる
@echo off echo shift 前 %%0: %0 shift echo shift 後 %%0: %0 :: → shift 後、%0 は元の %1 の内容になる! :: → %~nx0(スクリプト名取得)は shift 前に変数に保存しておく :: OK: スクリプト名を事前に保存 set "SCRIPT_NAME=%~nx0" shift echo スクリプト名: %SCRIPT_NAME%
落とし穴4:%* は shift しても変わらない
@echo off echo shift前 %%*: %* shift echo shift後 %%*: %* :: → %* は shift の影響を受けず、常に最初の引数リストを保持する :: 全引数を shift しながら処理する場合は %1 ループを使う
この挙動は 変数展開が思った通りに動かない原因と修正方法でも詳しく解説しています。
落とし穴5:引数に特殊文字(& ^ | など)が含まれると誤動作
:: NG: 特殊文字を含む引数をそのまま処理するとコマンドが壊れる script.bat "data&info.csv" :: → & がコマンド区切りとして解釈される場合がある :: OK: バッチ内では変数経由でアクセス(" で囲んで保護) set "FILE=%~1" echo ファイル: "%FILE%" :: OK: 呼び出し元で ^ でエスケープする script.bat "data^&info.csv"
10. 実践例3本
実践例1:汎用ファイル変換スクリプト(入出力パス引数)
@echo off
setlocal
:: ===================================================
:: convert.bat 入力ファイル [出力フォルダ] [/verbose]
:: ===================================================
set "SCRIPT=%~nx0"
set "VERBOSE=0"
set "INPUT="
set "OUTPUT="
:parse
if "%~1"=="" goto :end_parse
if /i "%~1"=="/verbose" ( set "VERBOSE=1" & shift & goto :parse )
if not defined INPUT ( set "INPUT=%~1" & shift & goto :parse )
if not defined OUTPUT ( set "OUTPUT=%~1" & shift & goto :parse )
shift
goto :parse
:end_parse
:: 必須チェック
if not defined INPUT (
echo 使い方: %SCRIPT% 入力ファイル [出力フォルダ] [/verbose]
exit /b 1
)
if not exist "%INPUT%" (
echo [ERROR] 入力ファイルが見つかりません: %INPUT%
exit /b 1
)
:: デフォルト出力先(入力ファイルと同じフォルダ)
if not defined OUTPUT set "OUTPUT=%~dp1"
if not exist "%OUTPUT%\" mkdir "%OUTPUT%"
if "%VERBOSE%"=="1" (
echo [詳細] 入力: %INPUT%
echo [詳細] 出力先: %OUTPUT%
)
:: 変換処理本体
copy "%INPUT%" "%OUTPUT%\%~n1_converted%~x1" >nul
echo [OK] 変換完了: %OUTPUT%\%~n1_converted%~x1
実践例2:複数ファイルをまとめて処理(可変長引数)
@echo off
setlocal enabledelayedexpansion
:: ===================================
:: archive.bat ファイル1 ファイル2 ...
:: ===================================
if "%~1"=="" (
echo 使い方: %~nx0 ファイル1 [ファイル2 ...]
exit /b 1
)
set "ARCHIVE=C:\work\archive_%date:~0,4%%date:~5,2%%date:~8,2%.zip"
set "TMP_LIST=C:\work\tmp_filelist.txt"
if exist "%TMP_LIST%" del "%TMP_LIST%"
:: すべての引数をリストに追加
set "CNT=0"
:add_loop
if "%~1"=="" goto :add_done
if not exist "%~1" (
echo [WARN] ファイルが見つかりません: %1
) else (
echo %~1 >> "%TMP_LIST%"
set /a CNT+=1
)
shift
goto :add_loop
:add_done
if !CNT! EQU 0 (
echo [ERROR] 有効なファイルがありません
exit /b 1
)
echo !CNT! 件のファイルをアーカイブします: %ARCHIVE%
powershell -NoProfile -Command "Compress-Archive -Path (Get-Content '%TMP_LIST%') -DestinationPath '%ARCHIVE%' -Force"
del "%TMP_LIST%" >nul
echo [OK] アーカイブ完了
実践例3:デプロイスクリプト(名前付き引数 + フラグ引数)
@echo off
setlocal enabledelayedexpansion
:: ============================================================
:: deploy.bat /env:production /src:C:\build /dryrun /verbose
:: ============================================================
set "ENV="
set "SRC="
set "DRYRUN=0"
set "VERBOSE=0"
:parse
if "%~1"=="" goto :end_parse
set "A=%~1"
if /i "!A:~0,5!"=="/env:" ( set "ENV=!A:~5!" & shift & goto :parse )
if /i "!A:~0,5!"=="/src:" ( set "SRC=!A:~5!" & shift & goto :parse )
if /i "!A!"=="/dryrun" ( set "DRYRUN=1" & shift & goto :parse )
if /i "!A!"=="/verbose" ( set "VERBOSE=1" & shift & goto :parse )
echo [WARN] 不明な引数: %1 (無視します)
shift & goto :parse
:end_parse
:: 必須引数チェック
if not defined ENV ( echo [ERROR] /env:環境名 を指定してください & exit /b 1 )
if not defined SRC ( echo [ERROR] /src:ソースパス を指定してください & exit /b 1 )
if not exist "%SRC%\" ( echo [ERROR] ソースパスが見つかりません: %SRC% & exit /b 1 )
if "%VERBOSE%"=="1" (
echo ========== デプロイ設定 ==========
echo 環境 : %ENV%
echo ソース: %SRC%
echo ドライラン: %DRYRUN%
echo ==================================
)
if "%DRYRUN%"=="1" (
echo [DRYRUN] xcopy "%SRC%\*" "D:\deploy\%ENV%\" /e /y
exit /b 0
)
xcopy "%SRC%\*" "D:\deploy\%ENV%\" /e /y >nul
if errorlevel 1 ( echo [ERROR] デプロイ失敗 & exit /b 1 )
echo [OK] %ENV% にデプロイしました
11. まとめ
| 場面 | 使う構文・テクニック |
|---|---|
| 基本的な引数受け取り | %1 %2 %3 |
| 引用符を除く・パス展開 | %~1 %~f1 %~dp1 %~nx1 |
| 全引数をまとめて | %*(shift の影響を受けない) |
| 可変長引数のループ | shift + goto ループ |
| スペース含むパスの安全な受け渡し | 渡し側: "パス" / 受け側: %~1 |
| オプション(名前付き/フラグ)引数 | shift ループで /key:value をパース |
| デフォルト値設定 | if not defined でフォールバック |
| 引数の存在・内容チェック | if "%~1"=="" / if not exist "%~1" |
FAQ
%1〜%9 は9個までしか直接アクセスできませんが、shift を使って順番に処理することで無制限に対応できます。shift ループで %1 を処理してから shift を呼ぶことで、10個目以降も %1 として受け取れます。set /a CNT+=1 してカウントするか、for %%A in (%*) do set /a CNT+=1 で数えます。ただし %* に引用符付き引数が含まれる場合は for の動作に注意が必要です。set "INPUT=%~1")してからサブルーチンを呼ぶ設計にしましょう。%~f1 はファイルが存在しなくても絶対パスを生成しますが、カレントディレクトリを基準にするため、実行フォルダによって結果が変わります。意図したパスになっているか echo %~f1 で確認し、if not exist "%~f1" で存在チェックを加えてください。%~dp0 でバッチファイルが置かれているフォルダパス(末尾 \ 付き)を取得できます。これを使うと、バッチファイルからの相対パスで他のファイルを参照できます(例: set "CFG=%~dp0config.ini")。
