シンボリックリンクは「実体は別の場所にあるが、見かけ上は指定した場所にあるように見えるエイリアス」です。設定ファイルを複数プロジェクトで共有したり、パス長問題を回避したり、ディスクを節約しながらファイルを「コピー」したように見せたりと、使いこなすと作業効率が上がります。
Windows では mklink コマンドでシンボリックリンク・ジャンクション・ハードリンクを作成できます。この記事では4種類のリンクの違いを整理したうえで、バッチファイルからの自動化パターンまで一通り解説します。
mklink コマンドの基本構文と4種類のリンク
mklink [オプション] リンク名 ターゲット オプションなし : ファイルへのシンボリックリンク /D : ディレクトリへのシンボリックリンク /H : ハードリンク(ファイルのみ) /J : ジャンクション(ディレクトリのみ)
引数の順番は「リンク名(作りたいパス)→ ターゲット(実体のパス)」です。コピーコマンドと逆になるので最初は戸惑いやすい点です。
4種類のリンク比較表
| 種類 | 対象 | クロスドライブ | 管理者権限 | 相対パス | 主な用途 |
|---|---|---|---|---|---|
| ファイルシンボリックリンク | ファイル | ○ | 通常は必要 | ○ | 設定ファイルの共有 |
| ディレクトリシンボリックリンク(/D) | ディレクトリ | ○ | 通常は必要 | ○ | フォルダエイリアス・デプロイ先切り替え |
| ジャンクション(/J) | ディレクトリ | ローカルのみ | 不要 | ×(絶対パスのみ) | フォルダの別名・旧パス互換 |
| ハードリンク(/H) | ファイル | ×(同ボリュームのみ) | 不要 | ○ | ファイルの複数エントリ・バックアップ |
迷ったらジャンクション(/J)が無難です。管理者権限が不要で、ディレクトリへのリンクを同一ドライブ内で作れます。ドライブをまたぐ場合やネットワークパスに対応したい場合はシンボリックリンク(/D)を使います。
ファイルシンボリックリンクを作成する
ファイルへのシンボリックリンクを作成します。リンクはオリジナルと同じように読み書きでき、削除してもオリジナルには影響しません。
@echo off
rem mklink リンク名 ターゲット(絶対パス推奨)
mklink "C:\work\config.ini" "D:\shared\config.ini"
if ERRORLEVEL 1 (
echo [ERROR] シンボリックリンクの作成に失敗しました。
echo 管理者権限で実行しているか確認してください。
) else (
echo [OK] シンボリックリンクを作成しました。
)
ディレクトリシンボリックリンクを作成する(/D)
ディレクトリへのシンボリックリンクです。フォルダのエイリアスを作ったり、デプロイ先を切り替えたりするのに使います。ネットワークパスを対象にすることも可能です。
@echo off
rem /D でディレクトリへのシンボリックリンク
mklink /D "C:\app\config" "D:\shared\app-config"
if ERRORLEVEL 1 (
echo [ERROR] 作成に失敗しました。管理者権限を確認してください。
) else (
echo [OK] ディレクトリシンボリックリンクを作成しました。
)
ジャンクションを作成する(/J)
ジャンクションは管理者権限なしで作れるディレクトリへのリンクです。同一ボリューム内ならパス長問題の回避にも使えます。パス長制限の最終手段集でも紹介しています。
@echo off rem /J でジャンクション(管理者権限不要・絶対パスのみ) mklink /J "C:\short" "C:\very\long\path\to\project\folder" echo ジャンクションを作成しました。
ジャンクションは 絶対パスのみ対応です。相対パスを指定しても自動的に絶対パスに変換されます。また、ネットワークパス(\\server\share)は対象にできません(その場合はシンボリックリンク /D を使う)。
ハードリンクを作成する(/H)
ハードリンクはファイルの「別名」です。同じファイルデータを指す複数のエントリを作れます。どちらから変更しても同期され、片方を削除してももう一方は残ります。
@echo off rem /H でハードリンク(同一ボリューム内のファイルのみ) mklink /H "C:\backup\report.xlsx" "C:\work\report.xlsx" echo ハードリンクを作成しました。
ハードリンクの注意点:同一ボリューム(ドライブ)内のファイルのみ対象です。ディレクトリには使えません。ファイルを「削除」しても、ハードリンクが残っているかぎりデータは消えません。fsutil hardlink list ファイル名 で同一データを参照しているすべてのパスを確認できます。
リンクの存在確認・種類を調べる
作成したリンクの種類は dir や fsutil で確認できます。
rem dir コマンドでリパースポイントのみを一覧表示 dir /AL "C:\work" rem fsutil でシンボリックリンク情報を確認 fsutil reparsepoint query "C:\app\config" rem ハードリンク数を確認(2以上でハードリンクあり) fsutil hardlink list "C:\work\report.xlsx"
dir /AL の出力例:
2024/03/01 10:00 <SYMLINKD> config [D:\shared\app-config] 2024/03/01 10:01 <JUNCTION> short [C:\very\long\path\...] 2024/03/01 10:02 <SYMLINK> config.ini [D:\shared\config.ini]
バッチファイルからリンクかどうかを判定するには dir の出力を findstr でフィルタリングします。
@echo off
set TARGET=C:\app\config
dir /AL "%TARGET%" 2>nul | findstr /i "<JUNCTION>" >nul
if %ERRORLEVEL%==0 (
echo %TARGET% はジャンクションです。
exit /b 0
)
dir /AL "%TARGET%" 2>nul | findstr /i "<SYMLINKD>" >nul
if %ERRORLEVEL%==0 (
echo %TARGET% はディレクトリシンボリックリンクです。
exit /b 0
)
echo %TARGET% は通常のディレクトリです。
リンクの存在チェックと条件分岐
IF EXIST による存在確認はリンク自体の存在チェックに使えます。ただし、リンク先のファイル・フォルダが存在しない「壊れたリンク」でも IF EXIST はリンク自体を検出します。
@echo off
set LINK=C:\app\config
set TARGET=D:\shared\app-config
rem リンク(またはフォルダ)の存在チェック
if exist "%LINK%\" (
echo リンクまたはフォルダが既に存在します。スキップします。
) else (
echo 存在しません。ジャンクションを作成します。
mklink /J "%LINK%" "%TARGET%"
if ERRORLEVEL 1 (
echo [ERROR] 作成に失敗しました。
exit /b 1
)
echo [OK] ジャンクションを作成しました。
)
リンクを削除する
シンボリックリンクやジャンクションの削除には 通常の rmdir / del を使います。リンク自体が削除されるだけで、リンク先のデータは消えません。
rem ディレクトリシンボリックリンク・ジャンクションの削除 rem ★ /s を付けると リンク先も再帰削除される危険あり ★ rmdir "C:\app\config" rem ファイルシンボリックリンク・ハードリンクの削除 del "C:\work\config.ini"
要注意:rmdir /s は使わないこと
ジャンクションやディレクトリシンボリックリンクに対して rmdir /s を実行すると、リンク先フォルダの中身まで再帰的に削除されます。必ず rmdir リンク名(/s なし)でリンク自体のみを削除してください。
@echo off
rem 複数のジャンクション・シンボリックリンクを一括削除
for %%L in (
"C:\app\config"
"C:\app\logs"
"C:\app\data"
) do (
if exist "%%~L\" (
rmdir "%%~L"
echo [OK] %%~L を削除しました。
) else (
echo [SKIP] %%~L は存在しません。
)
)
管理者権限が必要な場合の対処
シンボリックリンク(オプションなし・/D)の作成はデフォルトで管理者権限が必要です。管理者権限の自動取得と組み合わせるか、以下の方法で解決できます。
方法1:管理者権限チェック付きバッチ
@echo off
net session >nul 2>&1
if ERRORLEVEL 1 (
echo [ERROR] このスクリプトは管理者権限が必要です。
echo 右クリック→「管理者として実行」してください。
pause
exit /b 1
)
mklink /D "C:\app\config" "D:\shared\config"
echo [OK] 作成しました。
方法2:Developer Mode でシンボリックリンクを許可(Windows 10/11)
設定アプリ → システム → 開発者向け → 開発者モード を有効にすると、一般ユーザーでもファイル・ディレクトリシンボリックリンクを作成できます。開発マシンではこの設定を入れておくと便利です。
ジャンクション(/J)とハードリンク(/H)は管理者権限不要のため、権限が取れない環境では代替として使えます。
SUBST コマンドとの違い
似た用途に SUBST コマンド(パスに仮想ドライブレターを割り当てる)があります。違いを整理します。
| 項目 | mklink /J | SUBST |
|---|---|---|
| 管理者権限 | 不要 | 不要 |
| 再起動後 | 永続(レジストリ不要) | 消える(スタートアップに登録が必要) |
| アクセス方法 | フォルダパス | ドライブレター(例: X:\) |
| Explorer での見え方 | フォルダ(リンクマーク付き) | 仮想ドライブ |
| タスクスケジューラからのアクセス | ○ | △(別セッションでは見えないことがある) |
再起動しても消えない永続的なパスエイリアスが欲しい場合は mklink /J が適しています。短いドライブレターで参照したい場合や一時的な用途には SUBST が手軽です。
相対パスでシンボリックリンクを作成する
シンボリックリンクは相対パスで作成できます。ただし、相対パスはリンクが存在する場所を基準にします。バッチファイルの実行フォルダではない点に注意してください。
@echo off rem カレントディレクトリを移動してから相対パスでリンク作成 pushd "C:\projects\myapp" mklink /D "configs" "..\..\shared\configs" popd rem 相対パスリンクの確認: dir /AL で [..\..\shared\configs] と表示される dir /AL "C:\projects\myapp\configs"
%~dp0 を使ったパス取得と組み合わせると、バッチファイルの場所を基準にした相対リンクを確実に作れます。
@echo off rem バッチファイルの場所を基準にする set BAT_DIR=%~dp0 pushd "%BAT_DIR%" mklink /D "output" "..\build\release" popd echo [OK] %BAT_DIR%output → %BAT_DIR%..\build\release
実践パターン集
パターン1:設定ファイルを複数プロジェクトで共有する
同じ設定ファイルを複数プロジェクトで使い回したい場合、コピーして管理すると変更が同期されません。シンボリックリンクなら1か所を更新するだけで全プロジェクトに反映されます。
@echo off
setlocal
set SHARED=D:\shared
set PROJECTS=C:\projects\app1 C:\projects\app2 C:\projects\app3
for %%p in (%PROJECTS%) do (
rem 既存ファイルがあれば削除してからリンク作成
if exist "%%p\config.ini" del "%%p\config.ini"
mklink "%%p\config.ini" "%SHARED%\config.ini"
echo [OK] %%p\config.ini を共有しました。
)
パターン2:デプロイ先フォルダをジャンクションで切り替える
Blue/Green デプロイやバージョン切り替えに使えます。current というジャンクションが常に最新バージョンを指すようにしておけば、アプリはパスを変えずに最新版を参照できます。
@echo off
setlocal
set NEW_VERSION=C:\app\v2.0
set LINK=C:\app\current
rem 古いジャンクションを削除(リンク先は削除しない!rmdir /s は NG)
if exist "%LINK%\" (
rmdir "%LINK%"
echo [INFO] 旧バージョンリンクを削除しました。
)
rem 新バージョンへのジャンクション作成
mklink /J "%LINK%" "%NEW_VERSION%"
if ERRORLEVEL 1 (
echo [ERROR] リンク作成に失敗しました。
exit /b 1
)
echo [OK] %LINK% → %NEW_VERSION% に切り替えました。
パターン3:パス長制限を回避する
長いパスを持つプロジェクトでビルドや解析ツールがエラーになる場合、ジャンクションで短いパスを作ることで回避できます。詳しくはMAX_PATH 完全攻略を参照してください。
@echo off rem 長いパスを短いエイリアスにマップ(ジャンクション) mklink /J "C:\p" "C:\Users\username\Documents\projects\very-long-project-name" rem これで C:\p\src\main.c のような短いパスでアクセスできる echo C:\p を短縮パスとして使用できます。 echo 不要になったら rmdir C:\p で削除(/s は付けない)
パターン4:ログ・データフォルダをデータドライブに向ける
アプリがCドライブ固定のパスにログを書く場合、ジャンクションでDドライブのフォルダに向けることでCドライブの圧迫を防げます。
@echo off
setlocal
set APP_LOG=C:\app\logs
set DATA_LOG=D:\logs\app
rem データドライブにログフォルダを作成
if not exist "%DATA_LOG%" mkdir "%DATA_LOG%"
rem アプリの logs フォルダをバックアップして削除
if exist "%APP_LOG%\" (
echo 既存のログフォルダをリネームして退避します...
ren "%APP_LOG%" "logs_backup"
)
rem ジャンクションで向け直す
mklink /J "%APP_LOG%" "%DATA_LOG%"
echo [OK] %APP_LOG% → %DATA_LOG% にジャンクションを作成しました。
パターン5:一括セットアップスクリプト(作成&削除対応)
@echo off
setlocal enabledelayedexpansion
rem 引数: setup(作成)または teardown(削除)
if "%~1"=="teardown" goto TEARDOWN
:SETUP
echo リンクを作成します...
call :make_junction "C:\app\logs" "D:\logs\app"
call :make_junction "C:\app\data" "D:\data\app"
call :make_junction "C:\app\config" "D:\shared\config"
echo セットアップ完了。
exit /b 0
:TEARDOWN
echo リンクを削除します...
for %%L in ("C:\app\logs" "C:\app\data" "C:\app\config") do (
if exist "%%~L\" (
rmdir "%%~L"
echo [OK] %%~L を削除しました。
)
)
echo ティアダウン完了。
exit /b 0
:make_junction
rem %1=リンク名, %2=ターゲット
if exist "%~1\" rmdir "%~1"
mklink /J "%~1" "%~2"
if ERRORLEVEL 1 (
echo [ERROR] %~1 の作成に失敗しました。
) else (
echo [OK] %~1 → %~2
)
exit /b 0
よくあるトラブルと対処法
| エラー・症状 | 原因 | 対処法 |
|---|---|---|
| 「このコマンドの使い方は正しくありません」 | リンク名またはターゲットのパスに誤りがある | パスをダブルクォートで囲む。ターゲットは実在するパスを指定する |
| 「アクセスが拒否されました」 | シンボリックリンク作成に管理者権限が必要 | 管理者として実行する。または /J を使う。開発者モードを有効にする |
| 「既にファイルが存在します」 | 同名のファイル・フォルダ・リンクが既に存在 | 事前に del または rmdir でリンク/ファイルを削除する |
| ジャンクションからリンク先ファイルが消えた | rmdir /s でジャンクションを削除してしまった | 今後は rmdir(/s なし)でリンクのみ削除する。バックアップから復元 |
| dir で SYMLINK/JUNCTION と表示されない | dir に /AL オプションを付けていない | dir /AL パス で確認する |
| リンク経由でアクセスできない | リンク先が別ドライブで、ジャンクションを使っている | クロスドライブにはシンボリックリンク(/D)を使う |
| robocopy でリンク先の実体がコピーされる | robocopy のデフォルト動作がリンク先を辿る | robocopy /SL でリンク自体をコピーする |
| ジャンクションを作ったが再起動後に消えた | ジャンクションは消えない。ただしSUBSTは消える | dir /AL で確認する。SUBST と混同していないか確認 |
まとめ
| やりたいこと | コマンド | 権限 | 特徴 |
|---|---|---|---|
| ファイルのシンボリックリンク | mklink リンク名 ターゲット |
管理者 or Dev Mode | クロスドライブ○、相対パス○ |
| フォルダのシンボリックリンク | mklink /D リンク名 ターゲット |
管理者 or Dev Mode | クロスドライブ○、NW○ |
| ジャンクション(権限不要) | mklink /J リンク名 ターゲット |
不要 | ローカルのみ、絶対パスのみ |
| ハードリンク | mklink /H リンク名 ターゲット |
不要 | 同ボリューム・ファイルのみ |
| リンク一覧を確認 | dir /AL パス |
不要 | SYMLINKD / JUNCTION / SYMLINK |
| ジャンクション・ディレクトリリンクを削除 | rmdir リンク名(/s なし) |
不要 | /s を付けると実体も削除! |
| ファイルリンクを削除 | del リンク名 |
不要 | 実体は残る |
権限が取れない環境ではジャンクション(/J)、ドライブをまたぐ場合や相対パスが必要な場合はシンボリックリンク(/D)、ファイルデータを節約しつつ複数のパスから参照したい場合はハードリンク(/H)と使い分けてください。
よくある質問
/SL オプションを付けてください。xcopy には同等のオプションがなく、常にリンク先の実体がコピーされます。2>&1 でエラー出力をリダイレクトしてみてください。また、管理者権限が必要なケースで権限がない場合は「アクセスが拒否されました」のエラーが出ます。core.symlinks=true を有効にしてから管理者権限でクローンする必要があります。チームで共有する場合は全員の環境設定が必要になるため、ジャンクションをリポジトリ外で管理する方が運用しやすいことが多いです。

