【bat】%~dp0 完全ガイド|バッチファイルの場所を基準にファイル操作する方法・スペース対処・実践パターンまで徹底解説

【bat】バッチファイルで %dp0を使用して所在ディレクトリを基準にファイル操作を行う方法 bat

バッチファイルで %~dp0 を使うと、バッチファイルが置かれているディレクトリを基準にファイルやフォルダのパスを確実に指定できます。どこから実行しても(デスクトップのショートカット・タスクスケジューラ・他のバッチから call した場合も)バッチ自身の場所を正確に参照できるため、実務では必須の技術です。

この記事でわかること

  • %~dp0 の意味と %0 修飾子の仕組み
  • %~f0%~d0%~p0%~n0%~x0 等の修飾子一覧
  • 末尾の \ の活用とファイル名直結の書き方
  • パスにスペースが含まれる場合のダブルクォート対策
  • cd /d "%~dp0"pushd/popd の使い分け
  • サブディレクトリ・設定ファイル・ログファイルの管理パターン
  • 複数バッチのオーケストレーション実践例
スポンサーリンク

1. %~dp0 とは何か

%~dp0%0(バッチファイル自身のパス)に修飾子 ~d(ドライブ文字)と ~p(ファイルのあるパス)を組み合わせたものです。結果として「バッチファイルが存在するフォルダのフルパス(末尾 \ 付き)」が返ります。

@echo off
echo %~dp0
:: 実行結果例: C:\Users\tanaka\tools\
::  ↑ バッチファイルが C:\Users\tanaka\tools\myscript.bat にある場合

%0 は実行時のバッチファイルパスそのものですが、タスクスケジューラやショートカット経由で実行すると相対パスや省略形になることがあります。%~dp0 は常に絶対パスのドライブ+ディレクトリ部分を返すため安全です。

記述 展開される値の例 説明
%0 myscript.bat(相対パスの場合あり) バッチファイル名(実行時の指定方法に依存)
%~f0 C:\tools\myscript.bat フルパス(完全絶対パス)
%~d0 C: ドライブ文字のみ
%~p0 \tools\ パス部分のみ(ドライブなし・末尾 \
%~n0 myscript ファイル名(拡張子なし)
%~x0 .bat 拡張子のみ
%~nx0 myscript.bat ファイル名+拡張子
%~dp0 C:\tools\ ドライブ+パス(最もよく使う
%~dp1 C:\input\ 第1引数のドライブ+パス(引数にも使用可)
%~dp0 の末尾は必ず \ で終わる
%~dp0 の結果は C:\tools\ のように末尾が \ で終わります。そのため、ファイル名を直接連結できます: %~dp0config.iniC:\tools\config.ini\ を追加する必要はありません)。

2. 基本的な使い方

2-1. バッチと同じディレクトリのファイルにアクセスする

@echo off

:: バッチと同じディレクトリの config.ini を読み込む
set CONFIG=%~dp0config.ini

if not exist "%CONFIG%" (
    echo [ERROR] 設定ファイルが見つかりません: %CONFIG%
    exit /b 1
)

echo 設定ファイルを読み込みます: %CONFIG%
for /f "usebackq tokens=1,2 delims==" %%K in ("%CONFIG%") do (
    echo  %%K = %%L
)

2-2. ログファイルをバッチと同じ場所に出力する

@echo off

:: 日付付きログファイルをバッチのディレクトリに作成
set LOG_FILE=%~dp0logs\%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log

:: logs フォルダがなければ作成
if not exist "%~dp0logs\" mkdir "%~dp0logs"

echo [%DATE% %TIME%] 処理開始 >> "%LOG_FILE%"
echo 処理中... >> "%LOG_FILE%"
echo [%DATE% %TIME%] 処理完了 >> "%LOG_FILE%"
echo ログを出力しました: %LOG_FILE%

2-3. バッチ自身のファイル名・フルパスを取得する

@echo off

:: バッチ自身の各種情報を表示
echo フルパス     : %~f0
echo ドライブ     : %~d0
echo ディレクトリ : %~p0
echo ファイル名   : %~nx0
echo 拡張子なし   : %~n0
echo 所在フォルダ : %~dp0

3. パスにスペースが含まれる場合のダブルクォート対策

Program FilesMy Documents のようにパスにスペースが含まれる場合、%~dp0 をダブルクォートで囲まないとコマンドが誤動作します。常にダブルクォートで囲む習慣を付けましょう。

@echo off

:: NG: スペース入りパスで失敗する
copy %~dp0source.txt %~dp0destination.txt
:: → C:\Program Files\... の場合、"Files\..."以降が別引数として解釈される

:: OK: ダブルクォートで囲む
copy "%~dp0source.txt" "%~dp0destination.txt"

:: OK: 変数に入れてからダブルクォートで使う
set SRC=%~dp0source.txt
set DST=%~dp0destination.txt
copy "%SRC%" "%DST%"
スペースなしの環境でも将来のために常にダブルクォートを使う
現在の環境でスペースがなくても、他のPC・サーバーで実行されたときにパスにスペースが入って突然壊れることがあります。"%~dp0ファイル名" の形式で書く習慣をつけておくと安全です。スペース対処の詳細は パスにスペースが含まれているとエラーになるときの解決策 も参照してください。

4. cd /d “%~dp0” と pushd/popd でカレントディレクトリを変更する

タスクスケジューラや他のバッチから call されると、カレントディレクトリ(%CD%)がバッチの場所と異なる場合があります。冒頭で cd /d "%~dp0" を実行してカレントを合わせるのが定石です。

@echo off

:: バッチの場所にカレントディレクトリを移動(定番イディオム)
cd /d "%~dp0"

:: これ以降は相対パスでもバッチの場所を基準にできる
type config.ini
copy source.txt destination.txt
コマンド 説明 使いどき
cd /d "%~dp0" カレントをバッチの場所に変更(ドライブも変更) バッチの場所を基準に相対パスで操作したいとき
pushd "%~dp0" カレントを変更し、元の場所をスタックに保存 サブルーチン内など、後で元の場所に戻りたいとき
popd pushd で保存した場所に戻る pushd とセットで使う
@echo off

:: pushd/popd パターン(元のカレントに戻れる)
pushd "%~dp0"

:: バッチの場所で処理
echo 現在のディレクトリ: %CD%
type config.ini

:: 元のカレントに戻る
popd
echo 戻りました: %CD%
cd /d と pushd の違い
cd /d はカレントを変更するだけで元に戻れませんが、pushd は元の場所をスタックに積むので popd で元に戻れます。また pushd は UNCパス(\\server\share)にも対応しています(自動でネットワークドライブを割り当てる)。cd /d は UNCパスには対応していません。

5. サブディレクトリのファイルを操作する方法

%~dp0 の後ろにサブフォルダ名を続けることで、バッチの場所を起点にした相対的なサブディレクトリを指定できます。

@echo off

:: バッチの場所を基準に各ディレクトリを定義
set BASE_DIR=%~dp0
set INPUT_DIR=%~dp0input\
set OUTPUT_DIR=%~dp0output\
set LOG_DIR=%~dp0logs\

:: 必要なフォルダを作成
for %%D in ("%INPUT_DIR%" "%OUTPUT_DIR%" "%LOG_DIR%") do (
    if not exist %%D mkdir %%D
)

:: input フォルダ内の txt ファイルを output にコピー
for %%F in ("%INPUT_DIR%*.txt") do (
    echo コピー: %%~nxF
    copy "%%F" "%OUTPUT_DIR%"
)

5-1. 親ディレクトリ(一つ上)を参照する

@echo off

:: ..\ で一つ上のディレクトリを参照
set PARENT_DIR=%~dp0..\

:: for /f + cd で正規化(.. を解決したフルパスを取得)
pushd "%~dp0.."
set PARENT_DIR=%CD%\
popd

echo 親ディレクトリ: %PARENT_DIR%

:: 2つ上
pushd "%~dp0..\.."
set GRANDPARENT_DIR=%CD%\
popd
echo 2つ上: %GRANDPARENT_DIR%
%~dp0..\ の .. を正規化する方法
%~dp0..\ は動作しますが、パスに .. が残ったままになることがあります。pushd "%~dp0.." / set VAR=%CD%\ / popd の形で正規化すると、C:\tools\parent\ のようなすっきりしたパスになります。

6. 他のバッチや実行ファイルを呼び出す方法

6-1. call でサブバッチを呼び出す

@echo off

:: 同じディレクトリの他バッチを呼び出す
call "%~dp0setup.bat"
call "%~dp0lib\common.bat"

:: 引数を渡して呼び出す
call "%~dp0process.bat" "%~dp0input\" "%~dp0output\"

6-2. start で実行ファイルを起動する

@echo off

:: 同じディレクトリのツールを実行(パスに依存しない)
start "" "%~dp0tools\converter.exe" /input "%~dp0input\data.csv"

:: 同期実行(完了まで待つ)したい場合は call を使う
call "%~dp0tools\converter.exe" /input "%~dp0input\data.csv"

callstart の違いについては CALL と START の違いを完全解説 も参照してください。

サブルーチンを使った高度な呼び出しパターンについては バッチファイルのサブルーチン完全ガイド も参照してください。

7. %~dp1 など引数(%1〜%9)にも使える

%~dp00 はバッチファイル自身を指しますが、19 に変えると第1〜第9引数のドライブ+パス部分を取得できます。「引数に渡されたファイルのディレクトリ」を使った処理に便利です。

@echo off

:: 使い方: myscript.bat C:\data\input.csv

if "%~1"=="" (
    echo 使い方: %~nx0 ファイルパス
    exit /b 1
)

:: 引数のファイル名と所在ディレクトリを分解
set INPUT_FILE=%~f1
set INPUT_DIR=%~dp1
set INPUT_NAME=%~n1
set INPUT_EXT=%~x1

echo ファイル    : %INPUT_FILE%
echo ディレクトリ: %INPUT_DIR%
echo ファイル名  : %INPUT_NAME%
echo 拡張子     : %INPUT_EXT%

:: 入力ファイルと同じディレクトリに出力ファイルを作成
set OUTPUT_FILE=%INPUT_DIR%%INPUT_NAME%_output%INPUT_EXT%
echo 出力先: %OUTPUT_FILE%

引数の扱い全般については バッチファイルで引数を渡す方法完全ガイド も参照してください。

8. よくある落とし穴と対処法

8-1. %dp0 と %~dp0 の違い(~の有無)

@echo off

:: NG: %dp0 はただの変数 dp0 と同じ意味(未定義なら空)
echo %dp0
:: → 空文字または未定義エラー

:: OK: ~ でクォートを取り除いてパスを展開する
echo %~dp0
:: → C:\tools\
%dp0 は間違い。正しくは %~dp0
%dp0 と書くと dp0 という名前の変数の値が展開されます(通常は空)。正しくは %~dp0(チルダ付き)です。タイプミスでデバッグに時間を取られやすいため注意してください。

8-2. UNCパス(ネットワーク共有)で cd /d が失敗する

@echo off

:: NG: UNCパスに cd /d は使えない
cd /d "\\server\share\tools"
:: → "CMD はUNCパスを現在のディレクトリとしてサポートしていません" エラー

:: OK: pushd を使う(自動でネットワークドライブを割り当て)
pushd "\\server\share\tools"
echo %CD%
:: → Z:\ など自動割り当てされたドライブで表示
popd

8-3. ショートカット経由で実行した場合の挙動

.lnk(ショートカット)からバッチを起動した場合、%~dp0 はショートカットのプロパティ「作業フォルダ」ではなく、バッチファイル本体の実際の場所を返します。意図した場所にあるファイルが見つからない場合は、バッチファイルの実際のパスを確認してください。

9. 実践例3本

実践例1:設定ファイル・ログファイルをバッチと同じ場所で管理する

ツールを配布するとき、バッチ・設定ファイル・ログを同じフォルダに置いて自己完結させるパターンです。インストール先が変わっても動作します。

@echo off
setlocal enabledelayedexpansion

:: ── パス定義(バッチの場所を基準に固定)──
set BASE=%~dp0
set CONFIG=%BASE%config.ini
set LOG_DIR=%BASE%logs
set LOG=%LOG_DIR%\%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log

:: logs フォルダ作成
if not exist "%LOG_DIR%\" mkdir "%LOG_DIR%"

:: 設定ファイルチェック
if not exist "%CONFIG%" (
    echo [ERROR] %CONFIG% が見つかりません >> "%LOG%"
    echo 設定ファイルが見つかりません: %CONFIG%
    exit /b 1
)

:: 設定読み込み(usebackq で %CONFIG% をファイルとして読む。スペース入りパス対応)
for /f "usebackq tokens=1,2 delims== eol=#" %%K in ("%CONFIG%") do (
    set %%K=%%L
    echo [CONFIG] %%K=%%L >> "%LOG%"
)

echo [%DATE% %TIME%] 処理開始 >> "%LOG%"

:: ... メイン処理 ...

echo [%DATE% %TIME%] 処理完了 >> "%LOG%"
echo 完了。ログ: %LOG%

実践例2:src/dist/logs の3ディレクトリ構成でファイルを処理する

ビルドツール風に src/dist/logs/ を整備して処理するパターンです。

@echo off
setlocal

:: ── ディレクトリ構成定義 ──
set SRC_DIR=%~dp0src\
set DIST_DIR=%~dp0dist\
set LOG_DIR=%~dp0logs\
set TOOLS_DIR=%~dp0tools\

:: 必要なフォルダを準備
for %%D in ("%DIST_DIR%" "%LOG_DIR%") do (
    if not exist %%D mkdir %%D
)

:: 入力チェック
if not exist "%SRC_DIR%" (
    echo [ERROR] src フォルダが見つかりません: %SRC_DIR%
    exit /b 1
)

:: src の .txt を dist にコピーして加工
set RESULT=0
for %%F in ("%SRC_DIR%*.txt") do (
    echo 処理: %%~nxF
    copy "%%F" "%DIST_DIR%"
    if errorlevel 1 (
        echo [ERROR] コピー失敗: %%~nxF
        set RESULT=1
    )
)

if "%RESULT%"=="0" (
    echo [OK] すべてのファイルを %DIST_DIR% にコピーしました
) else (
    echo [WARN] 一部のファイルでエラーが発生しました
)
exit /b %RESULT%

実践例3:メインバッチが複数のサブバッチをオーケストレーションする

1つのメインバッチから %~dp0 を使って複数のサブバッチを順番に呼び出し、エラーが発生したら中断するパターンです。大規模な自動化スクリプトの定番構成です。

@echo off
setlocal

:: ── main.bat: サブバッチのオーケストレーター ──
set SCRIPTS=%~dp0scripts\
set LOG=%~dp0logs\main_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log

if not exist "%~dp0logs\" mkdir "%~dp0logs"

echo ========================================
echo  メイン処理開始: %DATE% %TIME%
echo ========================================

:: 処理ステップを順番に実行
call :run_step "1_cleanup.bat"   "クリーンアップ"
call :run_step "2_download.bat"  "ダウンロード"
call :run_step "3_process.bat"   "データ処理"
call :run_step "4_report.bat"    "レポート生成"

echo 全ステップ完了
exit /b 0

:run_step
echo [STEP] %~2 開始... >> "%LOG%"
echo [STEP] %~2 開始...
call "%SCRIPTS%%~1"
if %errorlevel% neq 0 (
    echo [ERROR] %~2 で失敗しました (errorlevel=%errorlevel%) >> "%LOG%"
    echo [ERROR] %~2 で失敗しました。処理を中断します。
    exit /b 1
)
echo [OK] %~2 完了 >> "%LOG%"
exit /b 0

10. まとめ:%~dp0 チートシート

やりたいこと コード例 ポイント
バッチと同じフォルダのファイルを使う "%~dp0config.ini" 末尾 \ があるのでそのまま連結
サブフォルダのファイルを使う "%~dp0input\data.csv" フォルダ名を続けるだけ
親フォルダを参照する pushd "%~dp0.." / set P=%CD%\ / popd pushd で正規化
カレントをバッチの場所に変更 cd /d "%~dp0" ドライブ変更も必要なら /d
元のカレントに戻りたい場合 pushd "%~dp0" / ... / popd pushd/popd でスタック管理
バッチ自身のフルパスを取得 %~f0 ドライブ+パス+ファイル名
バッチ自身のファイル名だけ取得 %~nx0 名前+拡張子
引数のファイルが置かれた場所を取得 %~dp1 019 に変える
UNCパスに対応させる pushd "%~dp0"(cd /d は不可) pushd は自動でドライブ割り当て

パスやファイル名の取得方法全般については バッチファイルのパスやファイル名を取得する方法、相対パスの指定方法については バッチファイルで相対パスを指定する方法 も参照してください。

FAQ

Q%dp0 と %~dp0 どちらが正しいですか?

A%~dp0(チルダ付き)が正しい書き方です。%dp0dp0 という名前の環境変数を展開しようとするため、通常は空文字になります。~(チルダ)は %0 に含まれるクォートを取り除いてパス修飾子を適用するための記号です。

Q%~dp0 の末尾に \ はつきますか?

Aはい、%~dp0 の展開結果は必ず末尾が \ で終わります(例: C:\tools\)。そのため %~dp0config.ini のようにファイル名を直接続けて書けます。%~dp0\config.ini と書くと \ が二重になるので注意してください。

Qタスクスケジューラから実行すると %~dp0 がうまく動かないのですが。

Aタスクスケジューラでは「開始」フォルダが System32 などになっている場合があります。%~dp0 自体はバッチファイルの実際の場所を返すので正しい値が取れるはずですが、念のためバッチの冒頭に cd /d "%~dp0" を入れてカレントを合わせておくと安全です。

Q%~dp0 でネットワークドライブにアクセスできますか?

Aバッチファイルがネットワークパス(\\server\share\)に置かれている場合でも %~dp0 は正しくそのパスを返します。ただし cd /d "%~dp0" は UNCパスに対応していないため失敗します。UNCパスでカレントを変更するには pushd "%~dp0" を使ってください。

Qサブフォルダを2階層以上下に指定する方法は?

A%~dp0first\second\file.txt のように \ 区切りで続けるだけです。例: "%~dp0tools\bin\convert.exe"。フォルダ名にスペースが含まれる可能性があればダブルクォートで囲んでください。

Q%~dp0 を変数に入れておく方が良いですか?

Aバッチが長くなる場合は set BASE=%~dp0 で変数に入れておくと、%BASE%config.ini%BASE%logs\ のように簡潔に書けて可読性が上がります。特に同じパスを何度も使う実践例や複雑な処理では変数化を推奨します。