Windowsでシンボリックリンクを作るにはmklinkが使えるし、管理者権限なしでフォルダにリンクを張りたいならジャンクションでいいかも

会社で「Windowsだとシンボリックリンクが作れない」という話になった。 mklink で作れると話したら驚かれたのでメモ。

導入が Windowsでシンボリックリンクを作る | Developers.IO と全く同じだなぁ...

環境

Windows 10 Pro 64bit v1909、コマンドプロンプト Version 10.0.18363.1139。

docs.microsoft.com

mklink [オプション] <link> <target> で、シンボリックリンクなどのリンクを作成する。

link はリンク作成先、 target はリンクが指す実際のファイル/ディレクトリパスを、絶対パスまたは相対パスで指定する。

オプションで作成するリンクの種類が異なり、それぞれでファイルまたはディレクトリの指定可否が決まる。

オプション 作成されるリンク target指定先
未指定 ファイルのシンボリックリンク ファイル
/d フォルダのシンボリックリンク ディレクト
/h ハードリンク ファイル
/j ディレクトリジャンクション ディレクト

targetに相対パスを指定する際の注意

target相対パスを指定する場合、オプションによって、パスの起点となるディレクトリ位置が異なる。

未指定または /dシンボリックリンクを作成する場合は、 ln と同様、 link からの相対パスとなる。

/h でハードリンクを作成、または /jディレクトリジャンクションを作成する場合、コマンド実行しているカレントディレクトリからの相対パスとなる。

リンクを作成するディレクトリをカレントディレクトリとすれば、どの方法でも同じ相対パスで指定できる。

コマンド例

以下のディレクトリ構成で、 link ディレクトリ直下にリンクを作る場合。

C:\root
  ┣ target
  ┃  ┗ src
  ┃    ┗ exp.txt
  ┗ link
root直下でコマンド実行
リンク種類 コマンド
ファイルのシンボリックリンク mklink link\symlink_file ..\target\src\exp.txt
フォルダのシンボリックリンク mklink /d link\symlink_dir ..\target\src
ハードリンク mklink /h link\hardlink.txt target\src\exp.txt
ディレクトリジャンクション mklink /j link\junction target\src
link直下でコマンド実行
リンク種類 コマンド
ファイルのシンボリックリンク mklink symlink_file ..\target\src\exp.txt
フォルダのシンボリックリンク mklink /d symlink_dir ..\target\src
ハードリンク mklink /h hardlink.txt ..\target\src\exp.txt
ディレクトリジャンクション mklink /j junction ..\target\src

リンクの表示と確認

エクスプローラーでの表示

ファイルのシンボリックリンクは、ファイルの種類が「.symlink」、ファイルサイズが0になる。アイコンはファイルへのショートカットと同様。

また、ディレクトリのシンボリックリンクディレクトリジャンクションは、アイコンはフォルダへのショートカットと同じだが、ファイルの種類は「ショートカット」ではなく「ファイル フォルダー」となる。

f:id:hepokon365:20201024204000p:plain
コマンド例で作成したリンクの、エクスプローラーでの表示

dirコマンドでの表示

dir コマンドでの属性には、以下のように表示される。

また、シンボリックリンクディレクトリジャンクションには、リンク先のファイルパスが表示される。

C:\root\link>dir /o:gn
YYYY/MM/DD  HH:MI    <DIR>          .
YYYY/MM/DD  HH:MI    <DIR>          ..
YYYY/MM/DD  HH:MI    <JUNCTION>     junction [C:\root\target\src]
YYYY/MM/DD  HH:MI    <SYMLINKD>     symlink_dir [..\target\src]
YYYY/MM/DD  HH:MI       %FILE_SIZE% hardlink.txt
YYYY/MM/DD  HH:MI    <SYMLINK>      symlink_file [..\target\src\exp.txt]

相対パスでリンクを作成すると、シンボリックリンクの場合は ln と同様、相対パスを保持しているが、ディレクトリジャンクションの場合は絶対パスに変換される模様。

相対パスで作成したシンボリックリンクを移動すると、移動先からの設定されている相対パスと同名のファイル/ディレクトリがない限りリンクを開けなくなるが、ディレクトリジャンクションを移動しても、リンク先のパスが変わらなければ、問題なく開くことができる。

lsコマンドでの表示

Git Bashから ls コマンドを使うと、シンボリックリンクディレクトリジャンクションには、Linuxなどでの実行結果と同様、ファイル名の後ろに @ がつく。

また、 ls -l で、シンボリックリンクディレクトリジャンクションにはリンク先のパスが表示される。

ディレクトリジャンクションは、絶対パス指定のディレクトリのシンボリックリンク扱いの模様。

$ ls -1 --group-directories-first
junction@
symlink_dir@
hardlink.txt
symlink_file@

$ ls -l --group-directories-first
total 1
lrwxrwxrwx 1 ... 18 ... junction -> /c/root/target/src/
lrwxrwxrwx 1 ... 13 ... symlink_dir -> ../target/src/
-rw-r--r-- 2 ...  1 ... hardlink.txt
lrwxrwxrwx 1 ... 21 ... symlink_file -> ../target/src/exp.txt

リンクの削除

作成されたシンボリックリンクや、ディレクトリジャンクションに対し、 unlink のような削除用コマンドは用意されていない。

通常のファイルやディレクトリと同様、 rd/rmdirdel で削除可能。エクスプローラーからも削除できる。

ln コマンドとの違い

ln コマンドは ln [OPTION]... [-T] TARGET LINK_NAME なので、 mklink とは linktarget の順序が逆になる。

lnTARGET相対パス指定する際は、カレントディレクトリではなく LINK_NAME からの相対パスにする必要があるので、 mklink のほうがわかりやすい気もする。

一方、絶対パス指定であれば ln -s src dest で指定できるので ln のほうがシンプルか。

また、デフォルトではハードリンクが作成されるのも mklink と異なる(あまり ln をハードリンク作成に使うこともないとは思うが)。

注意点

シンボリックリンクの作成権限

オプション未指定、または /dシンボリックリンクを作成する場合、デフォルトでは権限がないため、 この操作を実行するための十分な特権がありません。 というエラーが発生する。

シンボリックリンクを作成するには、コマンドプロンプトを管理者権限で実行して実行するか、開発者モードを有効とする必要がある模様。

開発者モードを有効化するには、Windows10の「設定」>「更新とセキュリティ」>「開発者向け」から「開発者モード」を選択し、再起動する。

f:id:hepokon365:20201024170258p:plain

コマンドプロンプトからしか実行できない

PowerShellや、Git for Windowsに付属するGit Bashから実行しようとしても、エラーとなる。

PS C:\Users\hepokon365> mklink
mklink : 用語 'mklink' は、コマンドレット、関数、スクリプト ファイル、または操作可能なプログラムの名前として認識されま
せん。名前が正しく記述されていることを確認し、パスが含まれている場合はそのパスが正しいことを確認してから、再試行してく
ださい。

exeにパスを通そうと思って where mklink しても、ファイルパスが見つからない。

C:\Users\hepokon365>where mklink
情報: 与えられたパターンのファイルが見つかりませんでした。

どうやら、 cmd.exe の組み込みコマンドの模様。

例えばPowerShellから実行する場合、 Start-Process cmd "/c mklink ..."コマンドプロンプトを起動し、コマンドとして渡してやればいい。この時、 -Verb Runas オプションを使用すれば、管理者権限でコマンドプロンプトの実行が可能。

Start-Process -Verb Runas cmd "/c mklink /d <link> <target>"

なお、Git Bashでは ln が使えるが、 -s オプション付きで実行しても、ファイルコピーが行われるだけの模様。

振り返り

シンボリックリンクが作れるとはいえ、管理者権限または開発者モードを有効にしないと使えなかったりと制限が多い。

ディレクトリのシンボリックリンクを作る用途で、かつ作成後にターゲットディレクトリを移動することがないのであれば、 /j によるディレクトリジャンクションリンクが権限不要で同じように使えるため、そちらを検討してもよさそう。