ハードリンクとシンボリックリンクを扱う

ハードリンクとシンボリックリンクについて忘れるのでまとめておく。
試した環境はUbuntu12.04。
text.txtというファイルを作成してある。中身は「Hello, world!」という文字列。

$ ls -l
total 4
-rw-rw-r-- 1 tokibito tokibito 14  1月 11 11:57 test.txt
$ cat test.txt
Hello, world!

このファイルに対して、ハードリンクとシンボリックリンクを作成してみる。

リンクを作成

どちらもlnコマンドで作成する。シンボリックリンクの場合は-sオプションを指定する。

$ ln test.txt foo  # ハードリンクの作成
$ ln -s test.txt bar  # シンボリックリンクの作成
$ ls -l
total 8
lrwxrwxrwx 1 tokibito tokibito  8  1月 11 12:05 bar -> test.txt
-rw-rw-r-- 2 tokibito tokibito 14  1月 11 11:57 foo
-rw-rw-r-- 2 tokibito tokibito 14  1月 11 11:57 test.txt

lsコマンドの結果の2カラム目を見ると、fooとtext.txtは2になっている。これは、ファイルに対する参照カウントが2つということらしい。
シンボリックリンクの場合は、1カラム目の最初の文字がl(小文字のエル)になっている。また、リンク先のパスが「->」の後に表示される。
この例では同じディレクトリにリンクを作成しているので問題はないが、ハードリンクの場合、同一デバイス、パーティション上にしか作成できないことに注意が必要。
参照先が同じかどうかは、ls -liでiノード番号を見ることで確認できる。

$ ls -li
total 8
282380 lrwxrwxrwx 1 tokibito tokibito  8  1月 11 12:05 bar -> test.txt
282521 -rw-rw-r-- 2 tokibito tokibito 14  1月 11 11:57 foo
282521 -rw-rw-r-- 2 tokibito tokibito 14  1月 11 11:57 test.txt

fooとtest.txtのiノード番号が同じになっている。

リンクを移動

movedというディレクトリを作成し、ハードリンクfooとシンボリックリンクbarを移動してみる。

$ mkdir moved
$ mv foo moved/
$ mv bar moved/
$ tree
.
├── moved
│   ├── bar -> test.txt
│   └── foo
└── test.txt

1 directory, 3 files
$ cat moved/foo 
Hello, world!
$ cat moved/bar 
cat: moved/bar: No such file or directory

シンボリックリンクbarは、相対パスでtest.txtを指定したため、リンクを移動すると参照先が無効になった。一方、ハードリンクはリンクを移動しても参照可能。
シンボリックリンクは、作成時に相対パス絶対パスの指定で違いがあるので注意が必要。
シンボリックリンクを作成時に絶対パスで指定しておくと、リンクを移動しても参照可能となる。

$ ln -s /home/tokibito/sandbox/oslink/test.txt hoge
$ ls -l
total 8
lrwxrwxrwx 1 tokibito tokibito   38  1月 11 12:17 hoge -> /home/tokibito/sandbox/oslink/test.txt
drwxrwxr-x 2 tokibito tokibito 4096  1月 11 12:15 moved
-rw-rw-r-- 2 tokibito tokibito   14  1月 11 11:57 test.txt
$ mv hoge moved/
$ cat moved/hoge 
Hello, world!

リンク先ファイルを移動

リンク先のファイルを移動した場合、ハードリンクは参照可だが、シンボリックリンクは相対、絶対指定に関係なく参照できなくなる。

$ ls -l
total 8
lrwxrwxrwx 1 tokibito tokibito  8  1月 11 12:05 bar -> test.txt
-rw-rw-r-- 2 tokibito tokibito 14  1月 11 11:57 foo
lrwxrwxrwx 1 tokibito tokibito 38  1月 11 12:35 hoge -> /home/tokibito/sandbox/oslink/test.txt
-rw-rw-r-- 2 tokibito tokibito 14  1月 11 11:57 test.txt
$ mv test.txt test.txt.moved
$ ls -l
total 8
lrwxrwxrwx 1 tokibito tokibito  8  1月 11 12:05 bar -> test.txt
-rw-rw-r-- 2 tokibito tokibito 14  1月 11 11:57 foo
lrwxrwxrwx 1 tokibito tokibito 38  1月 11 12:35 hoge -> /home/tokibito/sandbox/oslink/test.txt
-rw-rw-r-- 2 tokibito tokibito 14  1月 11 11:57 test.txt.moved
$ cat foo
Hello, world!
$ cat bar
cat: bar: No such file or directory
$ cat hoge
cat: hoge: No such file or directory

リンク先ファイルを削除

リンク先のファイルを削除した場合、移動と同様にハードリンクの場合は参照可、シンボリックリンクの場合は参照不可となる。

$ rm test.txt
$ ls -l
total 4
lrwxrwxrwx 1 tokibito tokibito  8  1月 11 12:05 bar -> test.txt
-rw-rw-r-- 1 tokibito tokibito 14  1月 11 11:57 foo
lrwxrwxrwx 1 tokibito tokibito 38  1月 11 12:35 hoge -> /home/tokibito/sandbox/oslink/test.txt

test.txtを削除したことで、fooの参照カウントが2から1に減っていることがわかる。参照カウントが0になった時点で、ファイルの実体が削除されたことになる(ディスク領域が開放される)。

リンクを削除

リンクを削除した場合、リンク先のファイルは削除されない。ハードリンクの場合は参照カウントが減る。

$ ls -l
total 8
lrwxrwxrwx 1 tokibito tokibito  8  1月 11 12:05 bar -> test.txt
-rw-rw-r-- 2 tokibito tokibito 14  1月 11 11:57 foo
lrwxrwxrwx 1 tokibito tokibito 38  1月 11 12:35 hoge -> /home/tokibito/sandbox/oslink/test.txt
-rw-rw-r-- 2 tokibito tokibito 14  1月 11 11:57 test.txt
$ rm foo bar hoge
$ ls -l
total 4
-rw-rw-r-- 1 tokibito tokibito 14  1月 11 11:57 test.txt