ただの技術メモ

個人備忘録

ハードリンクとシンボリックリンクの挙動と使い道

リンクについてまとめていく。

コマンドの結果はmacOS Monterey 12.0.1での実行結果です。

リンクとは

リンクとは異なるパスで同じファイルやディレクトリにアクセスできるようにする仕組み。 Unixのリンクはハードリンクとシンボリックリンクの大きく2つの種類がある。

ハードリンクはlnコマンド、シンボリックリンクlnコマンドにsオプションを付けて以下のように作成する。

$ ln -s <リンク元のパス> <リンクを張るパス>

ハードリンクはファイルにのみリンクを張ることができるが、シンボリックリンクディレクトリにもリンクを貼ることができる。

ハードリンクとシンボリックリンクについて

ハードリンクについて

ハードリンクとは、広義には「あるinodeとそのファイルに付けれた名前との繋がり」のこと。 つまり「ハードリンクを張る」というのは同じinodeを参照する別名のファイルを作成するということである。

同じinodeを参照するのでファイルサイズなどのメタデータも同じで、参照しているデータブロックも同じ。

例えばこんなファイルを作成する。

❯ cat ~/Desktop/etc/hard-link-source.conf
The file for hard link.

lsコマンドでinode番号などを確認すると

❯ ls -li ~/Desktop/etc/hard-link-source.conf
45031490 -rw-r--r--  1  user-name  staff  59  2 12 15:18 /Users/user-name/Desktop/etc/hard-link-source.conf

ハードリンクを/etc/hard.confという名前で張る。

sudo ln ~/Desktop/etc/hard-link-source.conf /etc/hard-link.conf

lsコマンドでハードリンクを確認してみる。

❯ ls -li /etc/hard-link.conf
45031490 -rw-r--r--  2 user-name  staff  59  2 12 15:18 /etc/hard-link.conf

このように同じinode番号を持った別名のファイルができている。

先ほども説明したように、同じinode番号を持っているので同じinodeを参照しており、参照しているデータブロックも同じなため実データも同じである。

片方でファイルを編集すると、もう片方からファイル内容を確認しても変更が反映されている。

例えば~/Desktop/etc/hard-link-source.confからファイルを編集して、/etc/hard-link.confを確認すると

❯ cat /etc/hard-link.conf
The file for hard link.
New line by hard-link-source.conf.

ハードリンクは同じinode番号を持った別名のファイルを作るので、どちらが親でどちらが子かなどの主従関係はない。

シンボリックリンクについて

シンボリックリンクを張ると、別のinode番号を持つファイルを作成する。

ファイルの実体はリンク元のファイルパスだが、そのファイルパスを参照するのでcatコマンドなどでファイル内容を確認すると、リンク元のファイル内容と同じものが確認できる。 ファイルの実態はリンク元のファイルパスなのでファイル容量は非常に小さい。

以下のファイルを作成する。

❯ cat ~/Desktop/etc/symbolic-link-source.conf
The file for symbolic link.
❯ ls -li ~/Desktop/etc/symbolic-link-source.conf
45029769 -rw-r--r--  1 user-name  staff  28  2 12 14:44 /Users/user-name/Desktop/etc/symbolic-link-source.conf

リンクを貼る。

❯ sudo ln -s ~/Desktop/etc/symbolic-link-source.conf /etc/symbolic-link.conf
❯ ls -li /etc/symbolic-link.conf
45029868 lrwxr-xr-x  1 root  wheel  59  2 12 14:46 /etc/symbolic-link.conf -> /Users/user-name/Desktop/etc/symbolic-link-source.conf

このようにinode番号は異なる。 ハードリンクと同じように片方のファイルから変更を加えてももう片方から変更を確認することができる。

今度は/etc/symbolic-link.confから変更を加えて、~/Desktop/etc/symbolic-link-source.confを確認してみる。

❯ cat ~/Desktop/etc/symbolic-link-source.conf
The file for symbolic link.
New line by symbolic-link.conf.

その他の違い

それぞれの用途

ハードリンクを利用している「.」「..」の仕組み

前述したようにディレクトリのハードリンクを張ることは基本的にできない。

しかしコンピューター内部の処理ではディレクトリのハードリンクが使われている。

カレントディレクトリを表す「.」や1つ上のディレクトリを表す「..」はディレクトリへのハードリンクである。 これらのハードリンクはディレクトリ作成時に作成される。

ディレクトリを作成して確認してみる。

❯ mkdir ~/test

作成したtestというディレクトリの情報を確認してみる。

❯ ls -lid ~/test
45027781 drwxr-xr-x  2 user-name  staff  64  2 12 13:53 /Users/user-name/test

user-nameの前の数字はハードリンクの数で、testディレクトリへのハードリンクの数は2となっている。 つまり、testディレクトリをリンク元にしているハードリンクが2つあるということになる。

そもそもハードリンクとは、あるファイルのinodeとそのファイルにつけられた名前との繋がりのことなので、普通にファイルを作成するとそのファイルはハードリンクを1つ持つ。

ディレクトリの実体は、ディレクトリ配下のファイルのinode番号とファイル名のリストを格納したファイルなので、ディレクトリ自体がハードリンクとしてカウントされる。

もう1つ目はカレンとディレクトリ「.」である。

❯ ls -lia ~/test
total 0
45027781 drwxr-xr-x   2 user-name  staff    64  2 12 13:53 .
  362921 drwxr-xr-x+ 87 user-name  staff  2784  2 12 15:18 ..

このようにディレクトリ作成によってカレントディレクトリ「.」と1つ上のディレクトリ「..」が作成されている。

カレントディレクトリ「.」のinode番号はtestディレクトリと同じになっていて、ハードリンクなのが分かる。

このようにディレクトリ作成時にはディレクトリそのものとカレントディレクトリ「.」の2つによってハードリンクが2つカウントされる。

ちなみに同じくディレクトリ作成によって作成される1つ上のディレクトリ「..」は作成したディレクトリの1つ上のディレクトリへのハードリンクになっているので、testディレクトリの1つ上のディレクトリである~のinode番号と同じになっている。

❯ ls -lid ~
362921 drwxr-xr-x+ 87 user-name staff  2784  2 12 15:18 /Users/user-name

シンボリックの利用用途

例えば階層の違うファイルをGit管理したいときに使う。

元々Git管理されているのは~/service-nameだとして、設定ファイルは階層の違うディレクト/etc/hoge.confにあるとする。 /etc/hoge.confをGit管理下に置くには、まずGit管理下に設定ファイルをコピーする。

❯ cp /etc/hoge.conf ~/service-name/hoge.conf

コピーした内容を一旦コミットする。

次に元々あったファイルを削除してシンボリックリンクを張る。(confを参照しているサービス(Nginxとか)は再起動しないといけなそう)

❯ sudo rm /etc/hoge.conf
❯ sudo ln -s ~/service-name/hoge.conf /etc/hoge.conf