バッチファイルで相対パスを使うと、ファイルの配置場所が変わっても動くスクリプトが作れます。しかし .\ や ..\ はカレントディレクトリに依存するため、実行場所を変えると動かなくなるトラップがあります。
この記事では、%~dp0 でバッチファイルの場所を基準にする方法(これが最重要)から、cd /d による固定、pushd/popd、タスクスケジューラ対策まで、実践パターン付きで体系的に解説します。
・
.\ ..\ の基本構文と落とし穴・
%~dp0 でバッチ自身の場所を基準にする方法・
cd /d "%~dp0" でカレントディレクトリを固定する方法・pushd / popd で一時的にフォルダを移動する方法
・FOR文・CALL文でパスが壊れるケースと対処法
・タスクスケジューラ実行時に相対パスが機能しない問題の解決
・スペースを含むパスの安全な書き方
・複数パスを変数で管理する実践テンプレート
相対パスの基本構文
相対パスは「現在いるフォルダ(カレントディレクトリ)」を起点に記述するパスです。
| 表記 | 意味 | 例 |
|---|---|---|
.\ |
カレントディレクトリ(省略可) | .\data\file.txt |
..\ |
1階層上 | ..\config\settings.ini |
..\..\ |
2階層上 | ..\..\shared\template.csv |
sub\file |
カレントの配下(.\省略形) |
data\input.csv |
フォルダ構成の例
以下のようなフォルダ構成を例に説明します。
C:\project\ ├── scripts\ │ └── backup.bat ← このバッチを実行 ├── data\ │ └── input.csv ├── config\ │ └── settings.ini └── backup\
@echo off rem カレントディレクトリが C:\project\scripts\ の場合 rem 同じフォルダのファイル type ".\backup.bat" rem 1階層上(C:\project\)の data フォルダ copy "..\data\input.csv" "..\backup\input.csv" rem 1階層上の config フォルダ type "..\config\settings.ini"
.\ や ..\ は「今いる場所」から計算されます。バッチファイルをダブルクリックで実行した場合、タスクスケジューラから実行した場合、コマンドプロンプトから実行した場合でカレントディレクトリが異なり、パスが変わります。これが相対パスの最大の落とし穴です。絶対パスと相対パスの使い分け
| 絶対パス | 相対パス | |
|---|---|---|
| 書き方例 | C:\project\data\file.txt |
..\data\file.txt |
| メリット | どこから実行しても同じファイルを参照 | フォルダ構成ごと移動・配布できる |
| デメリット | パスが変わると動かなくなる | カレントディレクトリに依存する |
| 必須の場面 | 固定の場所にあるファイル(システム系) | 配布・移動するバッチ |
絶対パスはパス変更に弱く、素の相対パスはカレントディレクトリに依存します。
%~dp0(バッチ自身の場所)を基準にすることで、どこから実行してもバッチの場所から計算した正確なパスが得られます。%~dp0 でバッチファイルの場所を基準にする【最重要】
%~dp0 はバッチファイル自身が置かれているフォルダの絶対パスを返す特殊変数です。末尾に \ が付くため、ファイル名を続けて書けばパスが完成します。
@echo off echo バッチファイルの場所: %~dp0 rem → C:\project\scripts\
@echo off rem バッチと同じフォルダの config.ini を読む type "%~dp0config.ini" rem バッチから1階層上の data フォルダを参照 copy "%~dp0..\data\input.csv" "%~dp0..\backup\input.csv"
%~dp0 を使うべき理由
rem ★ 問題のある書き方(相対パスのみ) rem カレントディレクトリが C:\Users\user\ の状態でバッチを実行すると... C:\Users\user> C:\project\scripts\backup.bat rem .\data\input.csv → C:\Users\user\data\input.csv を探す(存在しない!)
rem ★ 正しい書き方(%~dp0 を使う) rem %~dp0..\data\input.csv → C:\project\data\input.csv を探す(常に正確!)
%~ 修飾子の一覧
%~dp0 の d p にはそれぞれ意味があります。組み合わせて使えます。
| 変数 | 意味 | 例(C:\project\scripts\backup.bat) |
|---|---|---|
%~0 |
バッチファイル名(引数0) | backup.bat(または呼ばれ方により変化) |
%~f0 |
フルパス(絶対パス) | C:\project\scripts\backup.bat |
%~d0 |
ドライブ名 | C: |
%~p0 |
パス(ドライブ名なし) | \project\scripts\ |
%~dp0 |
ドライブ+パス(フォルダ) | C:\project\scripts\ |
%~n0 |
ファイル名(拡張子なし) | backup |
%~x0 |
拡張子 | .bat |
%~nx0 |
ファイル名+拡張子 | backup.bat |
%~dp1 → 第1引数のフォルダパス%~nx2 → 第2引数のファイル名+拡張子パス・ファイル名取得の詳細は【bat】バッチファイルのパス・ファイル名取得完全ガイドを参照。
cd /d “%~dp0” でカレントディレクトリを固定する
バッチの冒頭に cd /d "%~dp0" を書くと、カレントディレクトリをバッチファイルの場所に移動します。これにより、.\ や ..\ がバッチの場所から計算されるようになります。
@echo off cd /d "%~dp0" rem 以降は .\ ..\ がバッチの場所基準で動く copy "..\data\input.csv" "..\backup\input.csv"
/d オプションが必要な理由
cd "%~dp0"(/d なし)ではドライブをまたげないcd だけでは同じドライブ内でしかディレクトリ移動できません。たとえばカレントが D:\work のときに C:\project\scripts へ移動しようとすると失敗します。/d オプションを付けることでドライブをまたいだ移動が可能になります。常に cd /d を使う癖を付けましょう。rem NG: ドライブをまたぐと失敗する cd "%~dp0" rem OK: /d オプションでドライブをまたいで移動 cd /d "%~dp0"
%~dp0 の直接指定 vs cd /d 後に相対パス
| 方法 | コード例 | メリット | デメリット |
|---|---|---|---|
| %~dp0 直接指定 | copy "%~dp0..\data\f.csv" "%~dp0..\bak\" |
どこからでも安全 | パスが長くなる |
| cd /d 後に相対パス | cd /d "%~dp0" |
パスがすっきりする | cd 後の処理に限定 |
cd /d "%~dp0" を実行しつつ、変数に %~dp0 を保存しておくと柔軟に使えます。pushd / popd で一時的にフォルダを移動する
pushd は現在の場所を記憶してから移動し、popd で元の場所に戻ります。処理の前後でフォルダを行き来する場面に便利です。
@echo off echo 現在地: %CD% rem data フォルダに一時的に移動 pushd "%~dp0..\data" echo 移動先: %CD% rem data フォルダ内で処理 for %%F in (*.csv) do echo %%F rem 元の場所に戻る popd echo 戻り先: %CD%
pushd の UNCパス対応
cd は \\server\share 形式のUNCパスに移動できませんが、pushd は自動でネットワークドライブを割り当ててから移動します。ネットワーク共有フォルダへのアクセスには pushd \\server\share が便利です。詳細は【bat】バッチファイルで共有フォルダにアクセスする方法を参照。@echo off rem NG: cd は UNCパスに移動できない cd \\server\share\data rem OK: pushd は UNCパスに自動でドライブ割り当てして移動 pushd \\server\share\data dir *.csv popd
pushd / popd vs cd /d の使い分け
| cd /d “%~dp0” | pushd / popd | |
|---|---|---|
| 元の場所に戻る | 戻れない(保存しない) | popd で確実に戻る |
| UNCパス対応 | なし | あり(自動ドライブ割り当て) |
| スタック | なし | 複数回 pushd をネスト可能 |
| バッチ終了時 | 任意 | popd 忘れでも終了時にクリア |
| 主な用途 | 全体のカレントディレクトリ固定 | 一時的な移動・UNCパスアクセス |
FOR文の中での相対パス・%~dpI
FOR文でファイルを処理するとき、ループ変数 %%I にも同じ修飾子が使えます。
@echo off
rem サブフォルダを含む全CSVファイルを処理
for /r "%~dp0..\data" %%F in (*.csv) do (
echo ファイル名: %%~nxF
echo フォルダ: %%~dpF
echo フルパス: %%~fF
copy "%%~fF" "%~dp0..\backup\"
)
| 変数 | 意味 | 用途 |
|---|---|---|
%%~fI |
フルパス | コピー・移動先の指定 |
%%~dpI |
フォルダパス(ドライブ含む) | 出力先フォルダの動的生成 |
%%~nxI |
ファイル名+拡張子 | ログ出力・リネーム |
%%~nI |
ファイル名(拡張子なし) | リネーム・判定 |
%%~xI |
拡張子 | 種別判定 |
%%~zI |
ファイルサイズ(バイト) | サイズ確認 |
cd に注意FOR文の中で
cd を実行するとカレントディレクトリが変わり、続くループの .\ パスが狂います。FOR文の中ではなるべく %%~fI(絶対パス)または %~dp0 ベースのパスを使いましょう。CALL文・サブルーティンでのパス継承
バッチから別のバッチを CALL で呼ぶ場合、呼び出し先の %~dp0 は呼び出し先バッチの場所を指します。
rem 呼び出し元: C:\project\scripts\main.bat rem 呼び出し先: C:\project\lib\helper.bat @echo off rem main.bat の %~dp0 = C:\project\scripts\ call "%~dp0..\lib\helper.bat"
rem helper.bat の中では... @echo off rem %~dp0 = C:\project\lib\ (helper.bat の場所) type "%~dp0config.txt" rem → C:\project\lib\config.txt
呼び出し元のパスを渡したいときは引数として渡します。
call helper.bat "%~dp0"呼び出し先では
%~dp1 で受け取れます。同一バッチ内のサブルーティン(:label)ではパスは変わらない
@echo off
set BASEDIR=%~dp0
call :CopyFiles
call :CleanUp
exit /b
:CopyFiles
rem %BASEDIR% を使えば安全
copy "%BASEDIR%..\data\*.csv" "%BASEDIR%..\backup\"
exit /b
:CleanUp
del "%BASEDIR%..\backup\*.tmp"
exit /b
複数パスを変数で管理する実践テンプレート
大規模なバッチでは冒頭でパス変数をまとめて定義しておくと管理しやすくなります。
@echo off
setlocal
rem === パス定義ブロック ===
set BASEDIR=%~dp0
set DATADIR=%BASEDIR%..\data
set OUTDIR=%BASEDIR%..\output
set LOGDIR=%BASEDIR%..\logs
set TMPDIR=%BASEDIR%..\tmp
set LOGFILE=%LOGDIR%\batch_%date:~0,4%%date:~5,2%%date:~8,2%.log
rem === 必要フォルダ作成 ===
for %%D in ("%OUTDIR%" "%LOGDIR%" "%TMPDIR%") do (
if not exist "%%~D" mkdir "%%~D"
)
rem === 処理 ===
echo [%date% %time%] 処理開始 >> "%LOGFILE%"
xcopy "%DATADIR%\*.csv" "%OUTDIR%\" /E /Y >> "%LOGFILE%" 2>&1
if %ERRORLEVEL% neq 0 (
echo [%date% %time%] エラー: コピー失敗 >> "%LOGFILE%"
exit /b 1
)
echo [%date% %time%] 処理完了 >> "%LOGFILE%"
endlocal
exit /b 0
・
set BASEDIR=%~dp0 を最初に定義 → 以降は %BASEDIR% を参照するだけ・
cd /d "%~dp0" を省略できる(パスを全て絶対指定しているため)・
setlocal で変数をスコープ内に閉じ込める・ダブルクリック・コマンドプロンプト・タスクスケジューラ、どこから実行しても動く
タスクスケジューラで実行すると相対パスが機能しない
タスクスケジューラからバッチを実行すると、カレントディレクトリが C:\Windows\System32 になるため、.\ 相対パスはすべて失敗します。
症状の確認
rem タスクスケジューラから C:\project\scripts\backup.bat を実行した場合 rem カレントディレクトリ = C:\Windows\System32 rem NG: .\data\input.csv → C:\Windows\System32\data\input.csv(存在しない) copy ".\data\input.csv" ".\backup\"
対策1(推奨):バッチ冒頭に cd /d “%~dp0”
@echo off cd /d "%~dp0" rem 以降は .\ ..\ がバッチの場所基準で動く
対策2(推奨):%~dp0 でパスを絶対指定
@echo off rem %~dp0 は実行場所に関係なく常にバッチの場所を返す set BASEDIR=%~dp0 copy "%BASEDIR%..\data\input.csv" "%BASEDIR%..\backup\"
対策3:タスクスケジューラの「開始(オプション)」フォルダを設定
プログラム/スクリプト: C:\project\scripts\backup.bat 開始(オプション): C:\project\scripts
パスにスペースが含まれる場合の注意
パスに半角スペースが含まれる場合(例:C:\My Documents\)は、必ずダブルクォーテーションで囲む必要があります。
rem NG: スペースで区切られて別の引数として解釈される copy C:\My Documents\file.txt C:\backup\ rem OK: ダブルクォーテーションで囲む copy "C:\My Documents\file.txt" "C:\backup\" rem %~dp0 は常に囲む(パスにスペースが含まれる可能性があるため) copy "%~dp0..\data\file.txt" "%~dp0..\backup\"
%~dp0 は常にダブルクォーテーションで囲むバッチファイルが
C:\My Project\scripts\ のようにスペースを含むフォルダに置かれた場合、%~dp0 にもスペースが含まれます。囲まないとエラーになるため、"%~dp0" が鉄則です。スペースを含むパスの詳細は【bat】パスにスペースが含まれているとエラーになるときの解決策を参照。
よくあるトラブルと解決法
ケース1:ダブルクリックでは動くがコマンドプロンプトから動かない
rem 症状: .\data\file.txt が見つからない rem 原因: コマンドプロンプトのカレントディレクトリがバッチの場所と異なる rem 解決: 冒頭に cd /d "%~dp0" を追加する @echo off cd /d "%~dp0" rem ← これを追加 type ".\data\file.txt"
ケース2:%~dp0 が “C:\Windows\System32\” になる
START コマンドで実行した場合に発生することがあります。確認方法:バッチに
echo %~f0 を追加して、フルパスを表示させる。解決:バッチ自身のフルパスが正しく解決されているか確認。
START "" /D "%~dp0" "%~f0" のように呼び出し方を変更する。ケース3:pushd しっぱなしでバッチが終了した
rem 症状: pushd の後に goto :eof して popd を通らなかった
rem 解決: エラー時も必ず popd を通るようにする
@echo off
pushd "%~dp0..\data"
xcopy *.csv "..\backup\" /Y
if %ERRORLEVEL% neq 0 (
popd rem ← エラー時も popd
exit /b 1
)
popd
exit /b 0
ケース4:FOR /R でファイルパスに余分なスペースが入る
rem 症状: %%~fF の末尾に余分なスペースが入り動作がおかしい
rem 原因: SET 命令の行末スペース、または引数の区切り文字問題
rem 解決: %%~fF を ""ダブルクォーテーションで囲む
for /r "%~dp0..\data" %%F in (*.csv) do (
copy "%%~fF" "%~dp0..\backup\" rem ← %%~fF を "" で囲む
)
ケース5:%~dp0 が UNC パスになってしまう
rem 症状: ネットワーク共有からバッチを実行すると %~dp0 が \\server\share\ になる rem 解決: ローカルにコピーしてから実行するか、cd /d を使って対応 @echo off rem UNCパスでも pushd なら移動できる pushd "%~dp0" echo カレント: %CD% popd
よくある質問
set BASEDIR=%~dp0 で変数化し、すべてのパスに %BASEDIR% を付ける方式が明確です。シンプルなバッチなら cd /d "%~dp0" で統一するのも分かりやすいです。大規模なバッチでは両方を組み合わせるのがベストプラクティスです。call helper.bat "%~dp0" のように引数として渡し、helper.bat 内では %~dp1 で受け取ります。サブバッチ内の %~dp0 は helper.bat 自身の場所を指すため、呼び出し元のパスは引数経由で渡す必要があります。/ ではなく \ を使います。2階層上は ..\..\ と書きます。ただしあまり深くなると可読性が落ちるため、%~dp0 から絶対パスで書く方が保守しやすいです。%~dp0 は引数修飾子でありローカル変数ではないため、setlocal の影響を受けません。ただし set BASEDIR=%~dp0 で変数に格納した場合、setlocal 内で定義したなら endlocal 後は消えます。setlocal の前に定義するか、endlocal & set BASEDIR=%BASEDIR% で引き継ぎます。\\?\ プレフィックスを使うか、レジストリで長いパスを有効化します。詳細は【bat】ファイルパスの長さ制限に引っかかったときの対処法を参照してください。まとめ
| やりたいこと | 方法 | 注意点 |
|---|---|---|
| 同じフォルダのファイルを参照 | .\file.txt または file.txt |
カレントディレクトリ依存 |
| 1階層上のフォルダを参照 | ..\folder\file.txt |
カレントディレクトリ依存 |
| バッチの場所を基準にする | "%~dp0file.txt" |
常に " で囲む |
| カレントディレクトリを固定 | cd /d "%~dp0" |
/d 必須(ドライブまたぎ対応) |
| 一時的にフォルダ移動 | pushd "%~dp0..\data" / popd |
エラー時も popd を通す |
| 複数パスを一元管理 | set BASEDIR=%~dp0 で変数化 |
setlocal の前に定義する |
| FOR文でファイルを処理 | %%~fF(絶対パス)を使う |
FOR内で cd しない |
| タスクスケジューラ対策 | 冒頭に cd /d "%~dp0" |
または %~dp0 ベースで全パス指定 |
| UNCパスアクセス | pushd \\server\share |
cd は UNCパス不可 |
配布・移動するバッチには必ず冒頭に
cd /d "%~dp0" または set BASEDIR=%~dp0 を入れる。%~dp0 を使えば、ダブルクリック・コマンドプロンプト・タスクスケジューラ、どこから実行しても動くバッチが作れます。あわせて読みたい
- 【bat】%~dp0 完全ガイド|バッチファイルの場所を基準にファイル操作する方法
- 【bat】バッチファイルのパス・ファイル名取得完全ガイド|%~f0・%~dp0・%~nx0
- 【bat】バッチファイルで履歴を残してフォルダ間移動する方法完全ガイド|pushd・popd
- 【bat】タスクスケジューラから実行したときだけ動作が異なる原因と解決策
- 【bat】パスにスペースが含まれているとエラーになるときの解決策
- 【bat】ファイルパスの長さ制限に引っかかったときの対処法
- 【bat】バッチファイルでファイルをコピーする方法完全ガイド
- 【bat】バッチファイルで共有フォルダにアクセスする方法|UNCパス・net use

