【bat】バッチファイルで相対パスを指定する方法完全ガイド|%~dp0・cd /d・pushd・タスクスケジューラ対策・実践パターンまで

【bat】バッチファイルで相対パスを指定する方法 bat

バッチファイルで相対パスを使うと、ファイルの配置場所が変わっても動くスクリプトが作れます。しかし .\..\ はカレントディレクトリに依存するため、実行場所を変えると動かなくなるトラップがあります。

この記事では、%~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 でバッチファイルの場所を基準にする【最重要】

%~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 を探す(常に正確!)

%~ 修飾子の一覧

%~dp0d 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"
copy "..\data\f.csv" "..\bak\"
パスがすっきりする 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パス対応

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 ファイルサイズ(バイト) サイズ確認
FOR文の中では %~dp0 の値が変わることはありませんが、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 でフォルダパスを渡す場合
呼び出し元のパスを渡したいときは引数として渡します。
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
対策3だけでは不十分なケースがあります(サービス実行やシステムアカウント実行)。対策1または対策2をバッチ内に書いておくのがベストです。タスクスケジューラとバッチの詳細は【bat】タスクスケジューラから実行したときだけ動作が異なる原因と解決策を参照。

パスにスペースが含まれる場合の注意

パスに半角スペースが含まれる場合(例: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

よくある質問

%~dp0 と cd /d “%~dp0” はどちらを使うべき?
パスが多い場合は set BASEDIR=%~dp0 で変数化し、すべてのパスに %BASEDIR% を付ける方式が明確です。シンプルなバッチなら cd /d "%~dp0" で統一するのも分かりやすいです。大規模なバッチでは両方を組み合わせるのがベストプラクティスです。
%~dp0 のように %~dp0 をサブバッチに引き継ぐには?
call helper.bat "%~dp0" のように引数として渡し、helper.bat 内では %~dp1 で受け取ります。サブバッチ内の %~dp0 は helper.bat 自身の場所を指すため、呼び出し元のパスは引数経由で渡す必要があります。
相対パスで2階層以上上がるとき、../../ みたいに書けない?
バッチでは / ではなく \ を使います。2階層上は ..\..\ と書きます。ただしあまり深くなると可読性が落ちるため、%~dp0 から絶対パスで書く方が保守しやすいです。
setlocal を使うと %~dp0 が取れなくなる?
なりません。%~dp0 は引数修飾子でありローカル変数ではないため、setlocal の影響を受けません。ただし set BASEDIR=%~dp0 で変数に格納した場合、setlocal 内で定義したなら endlocal 後は消えます。setlocal の前に定義するか、endlocal & set BASEDIR=%BASEDIR% で引き継ぎます。
パスの長さ制限(260文字)に引っかかったらどうする?
Windows の MAX_PATH 制限(260文字)を超えると処理が失敗します。\\?\ プレフィックスを使うか、レジストリで長いパスを有効化します。詳細は【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 を使えば、ダブルクリック・コマンドプロンプト・タスクスケジューラ、どこから実行しても動くバッチが作れます。

あわせて読みたい