lnコマンドで作成するリンクの勉強をしようとしたら、思っていたより複雑だった

`ln`コマンドで生成するリンクのことを良く分かっていなかったので勉強しました。長いので最後にまとめがあります。

#使ってみましょう
##ファイルの作成
準備としてダミーファイルを作成します。ファイルの内容は'Hello, Qiita!'にしましょう。

```bash
[centos@ip-10-0-1-10 ~]$ echo 'Hello, Qiita!' > target
[centos@ip-10-0-1-10 ~]$ ls -i
12843345 target
```

`ls -i`は、ファイルのiノード番号を表示するコマンドです。iノード番号とは、ファイルとディスク上に存在するファイルの実体データを対応させる番号のことです。ファイルとiノード番号とデータは次のような関係になっています。

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| target | 12843345 | Hello, Qiita! |

##ln　（ハードリンク）
オプション無しの`ln target link1`でリンクを作成します。

```bash
[centos@ip-10-0-1-10 ~]$ ln target link1
[centos@ip-10-0-1-10 ~]$ ls -i
12843345 link1  12843345 target
```

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| link1 | 12843345 | Hello, Qiita! |
| target | 12843345 | Hello, Qiita! |

このように作成するリンクをハードリンクと呼びます。targetとlink1は同じiノード番号を持つため、ディスク上で全く同じデータを参照しています。確かめるためにちょっと実験をしてみましょう。

```bash
[centos@ip-10-0-1-10 ~]$ echo 'Hi, Qiita!' > target
[centos@ip-10-0-1-10 ~]$ cat link1
Hi, Qiita!
```

targetファイルの内容を上書きしたところ、link1の内容も変化しました。

ハードリンクには「リンク」と名が付いていますが、作成した後はどちらが元のファイルでどちらがリンクであるかという区別はつきません（実体は全く同じですから！）。どのような場面で利用するのかは良く分かりません。

##cp　（コピー）
ハードリンクに似たようなコマンドで、非常に良く使われる`cp`コマンドがあります。iノード番号に注意してみると、lnとの違いが分かりやすくなります。

```bash
[centos@ip-10-0-1-10 ~]$ cp target copy1
[centos@ip-10-0-1-10 ~]$ ls -i
12843349 copy1  12843345 link1  12843345 target
```

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| copy1 | 12843349 | Hi, Qiita! |
| link1 | 12843345 | Hi, Qiita! |
| target | 12843345 | Hi, Qiita! |

iノード番号が違うので、copy1はtargetとは全く別のものです。どちらかの内容を変更しても、もう一方には影響がありません。一般的なファイルのコピーはこちらですね。

##ln -s　（シンボリックリンク）
`ln`コマンドに`-s`オプションをつけることで、シンボリックリンクと呼ばれるリンクを作成することができます。一般的にリンクと言う場合にはこのシンボリックリンクを指す事が多いです。

```bash
[centos@ip-10-0-1-10 ~]$ ln -s target link2
[centos@ip-10-0-1-10 ~]$ ls -li
total 12
12843349 -rw-rw-r--. 1 centos centos 11 Aug 31 13:40 copy1
12843345 -rw-rw-r--. 2 centos centos 11 Aug 31 13:01 link1
12843350 lrwxrwxrwx. 1 centos centos  6 Aug 31 13:40 link2 -> target
12843345 -rw-rw-r--. 2 centos centos 11 Aug 31 13:01 target
```

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| copy1 | 12843349 | Hi, Qiita! |
| link1 | 12843345 | Hi, Qiita! |
| link2 | 12843350 | (targetを参照) |
| target | 12843345 | Hi, Qiita! |

link2の内容はtargetと同一となります。targetの内容を変えるとlink2も変わります。逆にlink2の内容を変えるとtargetも変わります。

```bash
[centos@ip-10-0-1-10 ~]$ cat link2
Hi, Qiita!
[centos@ip-10-0-1-10 ~]$ echo 'Penguins like fish.' > target
[centos@ip-10-0-1-10 ~]$ cat link2
Penguins like fish.
```

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| copy1 | 12843349 | Hi, Qiita! |
| link1 | 12843345 | Penguins like fish. |
| link2 | 12843350 | (targetを参照) |
| target | 12843345 | Penguins like fish. |

```bash
[centos@ip-10-0-1-10 ~]$ echo 'Penguins swim fast.' > link2
[centos@ip-10-0-1-10 ~]$ cat target
Penguins swim fast.
```

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| copy1 | 12843349 | Hi, Qiita! |
| link1 | 12843345 | Penguins swim fast. |
| link2 | 12843350 | (targetを参照) |
| target | 12843345 | Penguins swim fast. |

シンボリックリンク先を削除することもできます。この場合、あて先不在のリンクだけが残ります。

```bash
[centos@ip-10-0-1-10 ~]$ rm target
[centos@ip-10-0-1-10 ~]$ cat link2
cat: link2: No such file or directory
[centos@ip-10-0-1-10 ~]$ ls -li
total 8
12843349 -rw-rw-r--. 1 centos centos 11 Aug 31 13:40 copy1
12843345 -rw-rw-r--. 1 centos centos 20 Aug 31 14:38 link1
12843350 lrwxrwxrwx. 1 centos centos  6 Aug 31 13:40 link2 -> target
[centos@ip-10-0-1-10 ~]$
```

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| copy1 | 12843349 | Hi, Qiita! |
| link1 | 12843345 | Penguins swim fast. |
| link2 | 12843350 | (target[存在しない]を参照) |

ターゲットを再度作成することで、シンボリックリンクはそのまま使用できます。

```bash
[centos@ip-10-0-1-10 ~]$ echo 'Penguins are back now.' > target
[centos@ip-10-0-1-10 ~]$ ls -li
total 12
12843349 -rw-rw-r--. 1 centos centos 11 Aug 31 13:40 copy1
12843345 -rw-rw-r--. 1 centos centos 20 Aug 31 14:38 link1
12843350 lrwxrwxrwx. 1 centos centos  6 Aug 31 13:40 link2 -> target
12843351 -rw-rw-r--. 1 centos centos 23 Aug 31 14:42 target
[centos@ip-10-0-1-10 ~]$ cat link2
Penguins are back now.
[centos@ip-10-0-1-10 ~]$
```

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| copy1 | 12843349 | Hi, Qiita! |
| link1 | 12843345 | Penguins swim fast. |
| link2 | 12843350 | (targetを参照) |
| target | 12843351 | Penguins are back now. |

#シンボリックリンクのコピー
`cp`コマンドでリンクをコピーすることも出来ます。この場合、オプション無しではリンク参照先ファイルのコピーがファイルとして作成され、オプション`-d`を付けると同じターゲットを参照するシンボリックリンクが作成されます。

```bash
[centos@ip-10-0-1-10 ~]$ cp link2 copy2
[centos@ip-10-0-1-10 ~]$ ls -li
total 16
12843349 -rw-rw-r--. 1 centos centos 11 Aug 31 13:40 copy1
12843352 -rw-rw-r--. 1 centos centos 23 Aug 31 14:48 copy2
12843345 -rw-rw-r--. 1 centos centos 20 Aug 31 14:38 link1
12843350 lrwxrwxrwx. 1 centos centos  6 Aug 31 13:40 link2 -> target
12843351 -rw-rw-r--. 1 centos centos 23 Aug 31 14:42 target
```

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| copy1 | 12843349 | Hi, Qiita! |
| copy2 | 12843352 | Penguins are back now. |
| link1 | 12843345 | Penguins swim fast. |
| link2 | 12843350 | (targetを参照) |
| target | 12843351 | Penguins are back now. |

```bash
[centos@ip-10-0-1-10 ~]$ cp -d link2 copy3
[centos@ip-10-0-1-10 ~]$ ls -li
total 16
12843349 -rw-rw-r--. 1 centos centos 11 Aug 31 13:40 copy1
12843352 -rw-rw-r--. 1 centos centos 23 Aug 31 14:48 copy2
12843353 lrwxrwxrwx. 1 centos centos  6 Aug 31 14:52 copy3 -> target
12843345 -rw-rw-r--. 1 centos centos 20 Aug 31 14:38 link1
12843350 lrwxrwxrwx. 1 centos centos  6 Aug 31 13:40 link2 -> target
12843351 -rw-rw-r--. 1 centos centos 23 Aug 31 14:42 target
[centos@ip-10-0-1-10 ~]$
```

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| copy1 | 12843349 | Hi, Qiita! |
| copy2 | 12843352 | Penguins are back now. |
| copy3 | 12843353 | (targetを参照) |
| link1 | 12843345 | Penguins swim fast. |
| link2 | 12843350 | (targetを参照) |
| target | 12843351 | Penguins are back now. |

#mv　（ファイル名の変更）
`mv`はファイル名を変更するコマンドです。ファイルの持つiノード番号は変わりません。

```bash
[centos@ip-10-0-1-10 ~]$ mv copy1 copy11
[centos@ip-10-0-1-10 ~]$ ls -li
total 16
12843349 -rw-rw-r--. 1 centos centos 11 Aug 31 13:40 copy11
12843352 -rw-rw-r--. 1 centos centos 23 Aug 31 14:48 copy2
12843353 lrwxrwxrwx. 1 centos centos  6 Aug 31 14:52 copy3 -> target
12843345 -rw-rw-r--. 1 centos centos 20 Aug 31 14:38 link1
12843350 lrwxrwxrwx. 1 centos centos  6 Aug 31 13:40 link2 -> target
12843351 -rw-rw-r--. 1 centos centos 23 Aug 31 14:42 target
[centos@ip-10-0-1-10 ~]$
```

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| copy11 | 12843349 | Hi, Qiita! |
| copy2 | 12843352 | Penguins are back now. |
| copy3 | 12843353 | (targetを参照) |
| link1 | 12843345 | Penguins swim fast. |
| link2 | 12843350 | (targetを参照) |
| target | 12843351 | Penguins are back now. |

シンボリックリンクで指定されているファイルを`mv`した場合、シンボリックリンクはリンク切れとなります。シンボリックリンクが見ているのはリンク先のファイル名であって、iノード番号ではありません。

```bash
[centos@ip-10-0-1-10 ~]$ mv target target2
[centos@ip-10-0-1-10 ~]$ ls -li
total 16
12843349 -rw-rw-r--. 1 centos centos 11 Aug 31 13:40 copy11
12843352 -rw-rw-r--. 1 centos centos 23 Aug 31 14:48 copy2
12843353 lrwxrwxrwx. 1 centos centos  6 Aug 31 14:52 copy3 -> target
12843345 -rw-rw-r--. 1 centos centos 20 Aug 31 14:38 link1
12843350 lrwxrwxrwx. 1 centos centos  6 Aug 31 13:40 link2 -> target
12843351 -rw-rw-r--. 1 centos centos 23 Aug 31 14:42 target2
[centos@ip-10-0-1-10 ~]$
```

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| copy11 | 12843349 | Hi, Qiita! |
| copy2 | 12843352 | Penguins are back now. |
| copy3 | 12843353 | (target[存在しない]を参照) |
| link1 | 12843345 | Penguins swim fast. |
| link2 | 12843350 | (target[存在しない]を参照) |
| target2 | 12843351 | Penguins are back now. |

戻しておきます。

```bash
[centos@ip-10-0-1-10 ~]$ mv target2 target
[centos@ip-10-0-1-10 ~]$ ls -li
total 16
12843349 -rw-rw-r--. 1 centos centos 11 Aug 31 13:40 copy11
12843352 -rw-rw-r--. 1 centos centos 23 Aug 31 14:48 copy2
12843353 lrwxrwxrwx. 1 centos centos  6 Aug 31 14:52 copy3 -> target
12843345 -rw-rw-r--. 1 centos centos 20 Aug 31 14:38 link1
12843350 lrwxrwxrwx. 1 centos centos  6 Aug 31 13:40 link2 -> target
12843351 -rw-rw-r--. 1 centos centos 23 Aug 31 14:42 target
[centos@ip-10-0-1-10 ~]$
```

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| copy11 | 12843349 | Hi, Qiita! |
| copy2 | 12843352 | Penguins are back now. |
| copy3 | 12843353 | (targetを参照) |
| link1 | 12843345 | Penguins swim fast. |
| link2 | 12843350 | (targetを参照) |
| target | 12843351 | Penguins are back now. |

シンボリックリンクを`mv`した場合は、シンボリックリンク自身のファイル名が変わります。リンク先のファイルには影響がありません。

```bash
[centos@ip-10-0-1-10 ~]$ mv link2 link3
[centos@ip-10-0-1-10 ~]$ ls -li
total 16
12843349 -rw-rw-r--. 1 centos centos 11 Aug 31 13:40 copy11
12843352 -rw-rw-r--. 1 centos centos 23 Aug 31 14:48 copy2
12843353 lrwxrwxrwx. 1 centos centos  6 Aug 31 14:52 copy3 -> target
12843345 -rw-rw-r--. 1 centos centos 20 Aug 31 14:38 link1
12843350 lrwxrwxrwx. 1 centos centos  6 Aug 31 13:40 link3 -> target
12843351 -rw-rw-r--. 1 centos centos 23 Aug 31 14:42 target
[centos@ip-10-0-1-10 ~]$
```

| ファイル名 | iノード番号 | データ |
|:-:|:-:|:-:|
| copy11 | 12843349 | Hi, Qiita! |
| copy2 | 12843352 | Penguins are back now. |
| copy3 | 12843353 | (targetを参照) |
| link1 | 12843345 | Penguins swim fast. |
| link3 | 12843350 | (targetを参照) |
| target | 12843351 | Penguins are back now. |

#まとめ
とても長くなってしまったので、まとめます。

- ln: 同じiノード番号でファイルをコピーする。
- mv: 同じiノード番号でファイル名を変更する。
- ln -s: シンボリックリンクを作成する。
- cp: 異なるiノード番号でファイルをコピーする。シンボリックリンクを対象にした場合には、シンボリックリンクの参照先がコピーされる。
- cp -d: 異なるiノード番号でファイルをコピーする。シンボリックリンクを対象にした場合には、シンボリックリンク自身がコピーされる。

シンボリックリンクって何: 参照先ファイル名情報を持つ特殊なファイル。読み書きなどの操作は参照先ファイルに適用されるが、mvやrmやcp -dシンボリックリンク自身に適用される。
iノード番号って何：ファイル名とディスク上のデータを対応させる番号