rcmdnk's blog
Last update

20130625_symboliclink_200_200

Cygwinでシンボリックリンクをln -sコマンドで作るとExplorerから中身を見れないし、 Windowsでショートカットを作るとCygwinの中からは中身を正しく見ることができません。

CygwinをCygwin内だけで閉じてる場合は良いのですが、 Cygwin側からLinuxコマンドでWindows内のファイルを整理したり編集したいと思う場合これはとても不便です。

ということで今回はWindowsのシンボリック機能を使って両方で使えるリンクを作る方法についてです。

Windowsのシンボリックリンク

Windowsのショートカットはリンク先のパスが書かれたファイルで、 Linuxにおけるシンボリックリンクなどとは別物です。 従ってCygwinから見るとディレクトリもただの.lnkファイルで 中を無理やり見るとパスっぽいものが含まれた文字列が見れるだけです。

一方、LinuxのシンボリックリンクはWindowsはサポートしてないので、 Cygwinで作られたシンボリックリンクはExplorerなどでは通常ファイルに見え、 無理やりメモ帳などで開いてみると<symlink>を含むこちらもパスの情報の文字列が表示されます。

これではちょっと面倒なんですが、実はWindowsにもシンボリック機能があり、 Windows Vistaから使える様になってます 1 2

この機能はLinuxのそのものと近い機能になっているらしくCygwinからでもシンボリックリンクに見えます。

ですので両方でシンボリックリンクを使えば良いのですが、 通常はDOSプロンプト等からしか作れません。 いちいちOSプロンプトから作るのではやってられないので、 シンボリックリンクを簡単に作る方法を紹介します。

Explorer等からシンボリックリンクを作る

シンボリックを作る機能があるのにあまり知られてないのは、 右クリック等から作れるのはショートカットだけだからだと思います 3

そこで、 Link Shell Extension というソフトをインストールします。

このソフトをインストールすると、右クリックメニューにリンク元として作成と言う項目が出来、 あるファイルやフォルダでこの項目を選択肢、 他のフォルダで右クリックするとリンクを作成という項目が 選べる様になっているのでこれを選択するとシンボリックリンクが作成されます。 ショートカットと同じアイコンになります。

右クリックからプロパティをみてみると、リンクという項目があり、 シンボリックリンクであることが確認できます。 (下の絵はVista)

このファイルはCygwin側からはln -sで作ったものと全く同じに見えます。

CygwinでWindowsのシンボリックリンクを作る

まず、Cygwinでのコマンドの前に、DOSプロンプトでのシンボリックリンクの作り方について。

Windowsのシンボリックリンクはmklinkと言うコマンドで作れます。 DOSプロンプトでmklinkとしてみると

C:\>mklink
シンボリック リンクを作成します。

MKLINK [[/D] | [/H] | [/J]] リンク ターゲット

        /D          ディレクトリのシンボリック リンクを作成します。既定では、
                    ファイルのシンボリック リンクが作成されます。
        /H          シンボリック リンクではなく、ハード リンクを作成します。
        /J          ディレクトリ ジャンクションを作成します。
        リンク      新しいシンボリック リンク名を指定します。
        ターゲット  新しいリンクが参照するパス (相対または絶対)
                    を指定します。

となり、オプション無しならシンボリックリンク、さらにハードリンクや ジャンクション(Windowsの古いシンボリックリンク的な物)も 作れることが分かります。

lnコマンドと違い、フォルダ(ディレクトリ)指定の場合は/Dが必要です。

このコマンドをCygwinから呼ぶには

$ cmd /c mklink  target.txt original.txt

の様にcmdコマンドを使ってmklinkを呼び出します。 注意しなくてはいけないのは、リンク元とリンク先の順番がlnの場合と逆だ、ということです。 lnの場合は

$ ln -s original.txt target.txt

の様な形なので。

これを毎回打つのは大変だし、lnを使ったスクリプトも使い回しをしたいので、 次の様なWraper関数を作りました。

ln_windows_for_cygwin.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
if [[ "$OSTYPE" =~ "cygwin" ]];then
  function ln {
    opt="/H"
    if [ "$1" = "-s" ];then
      opt=""
      shift
    fi
    target="$1"
    if [ -d "$target" ];then
      opt="/D $opt"
    fi
    if [ $# -eq 2 ];then
      link="$2"
    elif [ $# -eq 1 ];then
      link=`basename "$target"`
    else
      echo "usage: ln [-s] <target> [<link>]"
      echo "       -s for symbolic link, otherwise make hard link"
      return
    fi
    t_winpath=$(cygpath -w -a "$target")
    t_link=$(cygpath -w -a "$link")
    echo "cmd /c mklink $opt $t_link $t_winpath"
    cmd /c mklink $opt "$t_link" "$t_winpath"
  }
fi

適当に.bashrc等に加えてください。 Cygwinであるかどうかのチェックも入れたので、 MacやLinuxと共通の.bashrcに入れてもOKです。

これで普通にln -s original.txt target.txtとすればtarget.txt というシンボリックリンクが出来ます。

Windows側から見るパスとCygwin内でのパスは違うので、 Windowsでのフルパスを取ってきて、それに対するシンボリックリンクを作っています 4

例えばC:\cygwin\home\user\a.txt というファイルに対してC:\cygwin\home\user\b.txtというリンクを作るとする (ついでにオリジナルのlnも作ってみる)と、

$ echo aaa > a.txt
$ ln -s a.txt b.txt          # using mklink
$ /usr/bin/ln -s a.txt c.txt # using original ln

とする、Cygwinで見ると

$ ls -l
-rw-r--r-- 1 user  None   4 Jun 25 23:00 a.txt
lrwxrwxrwx 1 user  None  23 Jun 25 23:01 b.txt -> /home/user/tmp/a.txt
lrwxrwxrwx 1 user  None   5 Jun 25 23:01 c.txt -> a.txt

となります。 どうやらWindowsのシンボリックリンクの方が色々20bytesほど情報が大きい様です。

さらに同じディレクトリにExplorerからショートカットを作ってみると

$ ls -l
-rw-r--r-- 1 user  None   4 Jun 25 23:00 a.txt
-rwxr-xr-x 1 Administrators None 736 Jun 25 22:12 a.txt.lnk
lrwxrwxrwx 1 user  None  23 Jun 25 23:01 b.txt -> /home/user/tmp/a.txt
lrwxrwxrwx 1 user  None   5 Jun 25 23:01 c.txt -> a.txt

と言った感じに、ショートカットが桁違いに大きいサイズです。 それでも1KB以下なのでよっぽどのことが無い限り問題ないわけですが、 さすがに10分の1以下で済むのであればシンボリックリンクを使いたいところです。 (互換性以外に何か問題はあるんでしょうか…?)

追記: 2015/01/25

コメントで教えてもらいましたが、 上の様にわざざlnmklinkにラッパーをかけなくても、 環境変数CYGWINwinsymlinksを設定することで Cygwinのln -sコマンドをWindowsのシンボリックリンク作成コマンドへ変更することができます。

Chapter 3 Using Cygwin Symbolic links

設定はWindowsの環境変数の方でするか、.bashrc等で、

1
2
3
if [[ "$OSTYPE" =~ cygwin ]];then
  export CYGWIN="winsymlinks $CYGWIN"
fi

とでもしておけばOK。CYGWINへはオプションを空白区切りで入れてく様なので デフォルトの値を残すように上の様に追加する形で設定。

これで通常のlnコマンドを使ってWindowsのシンボリックリンクが作れる様になります。

追記ここまで

追記: 2015/01/25

winsymlinksをちょっと勘違いしてましたが、上のリンク先ページをよく読めば分かるように、 winsymlinksだけを設定するとWindows側からはショートカットに見え、 Cygwinからはシンボリックリンクに見えるリンクができます。 (winsymlinks:lnkとしても同じ。)

winsymlinks:nativestrictとすると Windows側でもシンボリックリンクな機能のリンクができます。

ただし、この場合シンボリックリンクが作成できないような環境ではエラーが出ます。 (NTFSでしかサポートされないのでディスクがFATだったり、 またはWindows 10などでシンボリックリンクを禁止している場合や 管理者しか作成できない場合に通常ユーザーだった利するとき。)

winsymlinks:nativeとすると Windowsのシンボリックリンクを作れない場合には Cygwinの通常のシンボリックリンクを作ります。 つまり、Windowsのシンボリックリンクを扱えない時は Windows側からは使えないリンクになります。

  • winsymlinksまたはwinsymlinks:lnk: Windows側からショートカットに見えるリンクを作成。
  • winsymlinks:native: Windows側からシンボリックリンクに見えるリンクを作成。もしシンボリックリンク作成に失敗した場合、Cygwinの通常のシンボリックリンクを作る。(Windows側からは使えないリンクになる。)
  • winsymlinks:nativestrict: Windows側からシンボリックリンクに見えるリンクを作成。もしシンボリックリンク作成に失敗した場合はエラーを返す。

winsymlinks:lnkだと、通常の作業ではCygwinではシンボリックリンクだし Windowsではショートカットとして使えるのでほとんど問題はないのですが、 VimperatorやAutoHotKeyで メインファイルからさらに他のファイルを読み込んだりするとき、 きちんと見えなくてうまく動かない場合があります。

なのでできればすべてWindows側もシンボリックリンクにしておくと 一番問題なく使えるはずです。

追記ここまで

Sponsored Links
  1. シンボリック・リンクとジャンクションとハードリンクの違い

  2. Windows Vista/Windows Server 2008でシンボリック・リンクを作成する

  3. 古いバージョンとの互換性を考えると、XPが消える辺りで シンボリックリンクがデフォルトになってもよさそうなものですが。

  4. 相対パスでも良いのですが、絶対パスを使った時と場合わけが面倒なのと、 もし途中にオリジナルのlnを使ったリンクがあった場合、 Windowsでの絶対パスを取ってくれば確実にWindows側からでも見れる物になるので この様にしてあります。

Sponsored Links

« Cygwinにgit-1.8.3.1をインストール Mac(BSD)でcpをGNU的に使う + おまけ »

}