Linuxのファイルの種類

# はじめに
## 背景
`ls`や`find`と言ったコマンドで出力される情報として、「ファイルの種類」という項目もあります。
しかし、この「種類」に対しては意外とまとまった説明が見当たらないように思ったので、記事にまとめることにしました。

## 導入

ファイルの種類といっても、テキストデータかバイナリデータか、実行ファイル、画像ファイル、… etc.といった、**データの内容の種類 ( メディアタイプ ) の話は今回無関係**です。

一般にファイルというと、データを保存しておいて後で参照できるようにするための管理単位と認識されているかと思います。
基本はそれで問題ないのですが、Linux ( というかUNIX系のOS )では、**ファイルというのはデータを読み書きする機能を持ったもの**というもっと広い取り扱いがされるもので、機能的にいくつかの分類があるのです。

今回はその分類のお話です。

# 概要
## 大分類
ファイルというのは基本的に**読み書きいずれか、あるいは両方の操作ができるもの**です。
が、Linuxでは機能的に大きく2つに分かれます。

* 普通のファイル ( 「特殊」ではないものをまとめたもの )
  * 皆が大体想像している普通のファイル
  * 一般には、書き込んだデータを保存しておき、後に読み込んで同じデータが得られるようにするもの
  * しかし細かい機能はファイルシステムにより異なる
  * 種類としては、レギュラーファイル、ディレクトリ、シンボリックリンクの3種類が該当
* 特殊(スペシャル)ファイル ( XXスペシャルと呼ばれる )
  * 文字通り特殊なファイル
  * 特にファイルシステムの機能に依存しない
  * OS ( kernel ) 内部の機能を呼び出す「門」として働き、ファイルシステムそのものに影響は与えない
  * 種類としては、2種類のデバイスファイル ( ブロックデバイス/キャラクタデバイス )、パイプ ( FIFOスペシャル )、ソケットの4種類

## 無名ファイル

通常扱うファイルは、何かしら名前 ( ファイル名 ) がついているものです。しかし、一部には**名前のないファイル**として扱われるものもあります。

それらは一般のファイルシステムではなく、OS ( kernel ) の管理する特殊なファイル空間に配置されるような扱いとなります。
名前のあるファイルのようにはアクセスできないものの、機能的には同等の扱いとなることから、この記事ではまとめて扱うことにします。

# 普通のファイルの詳細
## レギュラーファイル
### レギュラーファイルの概要
文字通り、普通の中でもさらに普通のファイルです。

`ls -l`コマンドで出力すると、行頭のファイルの種類が`-`で表されます。

```shell-session:lsでのレギュラーファイルの出力
$ ls -l /bin/bash
-rwxr-xr-x. 1 root root 964608 10月 31  2018 /bin/bash
```

### レギュラーファイルの機能
一般に、作成したデータを書き込むことで保存し、後に読みだすことを目的に使うもので、大多数のファイルが該当します。
特に断りなく「ファイル」と言った場合はこのレギュラーファイルを指すと思って構いませんし、各種コマンド、リダイレクト操作、ファイル関連APIでは、このレギュラーファイルが作られます。

また、言うまでもないかもしれませんが、**プログラムとして実行するためのファイルもレギュラーファイル**です。
※例えばcatコマンドの実体が`/bin/cat`というレギュラーファイルだったり、など。一般に `/bin`,`/usr/bin`や`/sbin`,`/usr/sbin`に多数のプログラムが用意されています。

ただ、広い意味ではあくまで**読み込み・書き込みの片方あるいは両方ができるもの**なので、ファイルシステムによってはデータ保存以外の意味を持つ場合もあります。

## ディレクトリ
### ディレクトリの概要
ディレクトリは、ファイルの実体とファイル名の対応を管理するためのファイルです。

`ls -l`コマンドで出力すると、行頭のファイルの種類が`d`で表されます。

```shell-session:lsでのディレクトリの出力※-dオプション付き
$ ls -ld /home/angel
drwx------. 16 angel angel 4096  8月 23 22:19 /home/angel
```

### ディレクトリの機能
「ファイルの実体とファイル名の対応を管理」というだけではピンとこないかも知れません。しかし、**ファイルの実体は内部的には番号で管理されているため**、名前から対象のファイルを特定するために、番号⇔名前の対応付けが必要なのです。
この**対応を一覧で保持する**のがディレクトリであり、**個々の対応付けのことをハードリンクと言います**。
※ハードリンクは、後述するシンボリックリンクと対比されることがよくあります。これは、同一のファイルに対して複数の対応付け ( ハードリンク ) を作成することで、シンボリックリンクと類似の「ファイルの別名」を実現できるからです。

ディレクトリの保持する対応情報も ls コマンドで出力することができます。更に `-i`オプションも指定することで番号も併せて出力されます。
この番号のことを**i-node番号**と呼びます。

```shell-session:i-node番号付きの対応一覧出力
$ ls -la -i /home/angel  # 左端にi-node番号が出る
合計 32
18887020 drwx------. 16 angel angel 4096  8月 23 22:19 .
17042896 drwxr-xr-x.  3 root  root    19  5月  8 21:16 ..
18886815 -rw-------.  1 angel angel  620  8月 21 23:46 .ICEauthority
18886834 -rw-------.  1 angel angel  364  8月 23 23:43 .bash_history
18887021 -rw-r--r--.  1 angel angel   18 10月 31  2018 .bash_logout
18887022 -rw-r--r--.  1 angel angel  193 10月 31  2018 .bash_profile
18887023 -rw-r--r--.  1 angel angel  231 10月 31  2018 .bashrc
 1008924 drwx------. 14 angel angel 4096  8月 21 23:36 .cache
 1008921 drwxr-xr-x. 14 angel angel  261  8月 21 23:36 .config
…
```

この例だと、`/home/angel`というディレクトリに登録されている `.bashrc`という名前のファイルのi-node番号は 18887023 となっています。このように対応情報 ( ハードリンク ) があることで、このファイルの実体に対して `/home/angel/.bashrc` という名前をもとに操作できるようになるのです。
とは言え、**i-node番号を元にしてユーザが直接ファイルを操作することはできません**。あくまで内部的な管理・操作用です。

なお、ディレクトリの中にディレクトリの情報を登録することもできます。
これにより、あたかも物理的に箱が入れ子になっているかのように、階層的にファイルを管理できるようになっています。

ディレクトリの操作に関しては、「対応情報の管理」に特化したファイルであるため、好き勝手に読み書きができるわけではありません。
対応一覧情報の参照、対応付けの作成や削除、名前変更等、対応付けに関する操作のみとなっています。
※なんらかのファイルを作ることで、自動的に対応付けの作成も行われます。

## シンボリックリンク
### シンボリックリンクの概要
シンボリックリンクは、他のファイルを別名で操作するためのファイルです。

`ls -l`コマンドで出力すると、行頭のファイルの種類が`l`で表されます。

```shell-session:lsでのシンボリックリンクの出力
$ ls -l /bin
lrwxrwxrwx. 1 root root 7  5月  8 20:49 /bin -> usr/bin
$ ls -l /usr/bin/java
lrwxrwxrwx. 1 root root 22  5月  9 23:16 /usr/bin/java -> /etc/alternatives/java
```

### シンボリックリンクの機能
シンボリックリンクの機能は、読み書き操作があった場合に、参照先に設定されている他のファイルへ反映させることで、あたかも別名ファイルとして扱えるようにすることです。
この「他のファイル」というのはレギュラーファイルに限らず、ディレクトリ、それ以外の種類でも選ぶことが可能です。別のシンボリックリンクを参照して、更にその参照先を扱えるような構成をとることもできます。

加えて、`ls -l` 等で参照先がどこか分かるように情報提供する役割もあります。

ここで、上での出力例を再掲します。

```shell-session:lsでのシンボリックリンクの出力(再掲)
$ ls -l /bin
lrwxrwxrwx. 1 root root 7  5月  8 20:49 /bin -> usr/bin
$ ls -l /usr/bin/java
lrwxrwxrwx. 1 root root 22  5月  9 23:16 /usr/bin/java -> /etc/alternatives/java
```

一般には、シンボリックリンクがどのファイルを参照しているか、管理はファイル名で行います。ファイル名は相対パス・絶対パスどちらもあります。
上の例で、`/bin -> usr/bin`となってるのは相対パスの例です。「相対」で考える時の**ベースはシンボリックリンクのあるディレクトリ**となりますから、`/bin`は`/usr/bin` の別名 ( この例ではディレクトリ ) として働きます。例えば `/bin/cat` というファイル名で `/usr/bin/cat` というファイルを操作できる、といった具合です。
続いて、`/usr/bin/java -> /etc/alternatives/java` となっているのは絶対パスの例です。これはそのまま、`/usr/bin/java` というファイル名で `/etc/alternatives/java` というファイルを操作することができます。

なお、こういったシンボリックリンクは一般的に、それ自身「参照先のファイルの名前」を情報として持っているだけです。なので参照先のファイルが移動すると参照が無効になってしまいますし、逆に別のファイルが参照先のファイル名に移ってくると、参照しているファイルの実体が変わることになります。

# 特殊(スペシャル)ファイルの詳細
## 普通のファイルとの違い
[大分類](#大分類)で、特殊(スペシャル)ファイルに「OS ( kernel ) 内部の機能を呼び出す『門』として働き、ファイルシステムそのものに影響は与えない」という特徴があることを挙げました。

逆に言えば普通のファイルは、読み書きの操作の影響はあくまでファイルシステムそのものに及ぶものですが、特殊(スペシャル)はそうではないということです。

次の図では、特殊(スペシャル)ファイルの一例として、デバイスファイルのイメージを挙げますが、ファイルシステム内に保持している情報は「デバイス番号」という管理情報のみで、操作の影響はあくまでOS(kernel)を通じてファイルシステム外 ( この場合は実際のデバイス ) に行くことになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74396/3a69f0ec-7f96-38b4-9dfd-8f3355917191.png)

そういう意味では、他のファイルを参照するシンボリックリンクも特殊と言える気もしますが、影響はなんらかのファイルシステムに行きますので、分類するなら「普通」の方だと言えるでしょう。

## デバイスファイル
デバイスファイルには、ブロックデバイス ( ブロックスペシャル ) と、キャラクタデバイス ( キャラクタスペシャル ) の2種類があります。ここではまとめて紹介することにします。

### デバイスファイルの概要
デバイスファイルは、OS ( kernel ) の認識するなんらかの「デバイス」を操作するためのファイルです。

`ls -l`コマンドで出力すると、行頭のファイルの種類が`b`あるいは`c`で表されます。それぞれブロックデバイス、キャラクタデバイスに対応します。

```shell-session:lsでのデバイスファイルの出力
$ ls -l /dev/sda   # ブロックデバイスの例
brw-rw----. 1 root disk 8, 0  9月 14 19:52 /dev/sda
$ ls -l /dev/null  # キャラクタデバイスの例1
crw-rw-rw-. 1 root root 1, 3  9月 14 19:52 /dev/null
$ ls -l /dev/pts/0  # キャラクタデバイスの例2 ( PTY )
crw--w----. 1 root tty 136, 0  9月 15 01:39 /dev/pts/0
```

なお、どのデバイスファイルも**メジャー番号とマイナー番号**という2種類の数字が設定されており、`ls -l`でもその値が出力されます。
※上の例での `8, 0` や `1, 3` や `136 0` の部分、前の方がメジャー番号

### デバイスファイルの機能
デバイスファイルは、その名の通りデバイスを操作するためのファイルです。
「[普通のファイルとの違い](#普通のファイルとの違い)」で挙げたように、読み書き等操作の影響はファイルシステムそのものではなく、OS ( kernel ) のデバイスドライバを通じて、対応するデバイスに反映されます。

なお、デバイスといっても、`/dev/sda`のように実際にマシンに搭載しているディスク ( ハードディスクやSSD等 ) そのものであることもあれば、物理的なデバイスではなく OS ( kernel ) が仮想的に管理している `/dev/null`のようなデバイスもあります。
もっと身近なのは、SSH等でログインするとシェルの標準入出力先に接続されるTTY/PTYと言えるかもしれません。これもデバイスファイルで管理されます。
※記事「[標準入力・標準出力ってなに?](https://qiita.com/angel_p_57/items/03582181e9f7a69f8168#tty%E3%81%A8pty)」や、「[TTY/PTYに関するクイズ](https://qiita.com/angel_p_57/items/ff1c0d054714b7982ca5)」でTTY/PTYを取り上げています。

これらデバイスファイルは、一般的に`/dev`ディレクトリ内に、慣習的なルールに沿ったファイル名で配置されますが、別にどんな場所に、どんなファイル名で、どんなファイルシステムに作られたとしても機能は同じです。
あくまでデバイスファイルの機能を左右するのは、ファイルに設定されたメジャー番号・マイナー番号であり、この番号が OS ( kernel ) のどのドライバとどう連携するかを決めるのです。
`/dev/null`( 参考: [null(4)manページ](https://linuxjm.osdn.jp/html/LDP_man-pages/man4/null.4.html) ) がメジャー番号1、マイナー番号3というように固定されている場合もありますが、番号が動的に決まる場合もあります。

### ブロックデバイス・キャラクタデバイスの違い
さて、ここではブロックデバイス・キャラクタデバイスをまとめて説明しましたが、一応その違いについても触れておきます。

一応、ブロックデバイスは「(対象のデータを細切れにせずにまとめて)ブロック単位でデータ転送を行うもの」、キャラクタデバイスはその逆に「1文字単位でデータ転送を行うもの」となっていますが、実用上は単純に言うと、**ディスクのようにファイルシステムを構築できる、あるいは構築済みのファイルシステムを利用できるのがブロックデバイス**、その他全部がキャラクタデバイスです。

なお、デバイスとしてLANカード、Wifiアダプタのようなネットワークインターフェースを想像される方もいるかも知れませんが、実はこれらデバイスはブロックデバイス・キャラクタデバイス、どちらとしても管理されません。
ネットワークインターフェースを直に操作する場面はそうそうないと思いますが、これらの操作は後述するソケットを通じて行います。

## パイプ(FIFOスペシャル)
### パイプ(FIFOスペシャル)の概要
パイプは、FIFOという名前の通り、「書き込んだデータをその順に読み込むことができる」特殊なファイルです。
シェルで `command1 | command2` のようなコマンドでの実行を「パイプライン」と呼ぶように、この実行方法とも深い縁があります。

一般には無名のファイルとして、ファイルシステム上には見えない存在ですが、「名前付き」のパイプをファイルとして作成することもできます。
`ls -l`コマンドで出力すると、行頭のファイルの種類が`p`で表されます。

```shell-session:lsでのパイプの出力
$ ls -l /run/systemd/initctl/fifo 
prw-------. 1 root root 0  9月 14 19:52 /run/systemd/initctl/fifo
```

### パイプ(FIFOスペシャル)の機能
以前、「[標準入力・標準出力ってなに?](/angel_p_57/items/03582181e9f7a69f8168#%E3%83%AA%E3%83%80%E3%82%A4%E3%83%AC%E3%82%AF%E3%83%88%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3)」という記事で、パイプライン実行を次のような図で説明しました。

![パイプライン実行のイメージ](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F74396%2Ff9981eee-545e-e5d1-6f67-739e621abc53.png?ixlib=rb-1.2.2&auto=compress%2Cformat&fit=max&s=8d842c983f000281d9fd7c9e7fa5c72a)

この図の中で「パイプ」と書いてある部分が、本題のパイプ(FIFOスペシャル)にあたります。
このように、**書き込まれたデータを読み込み側にそのまま流し、それによって同一マシン上の別々のプロセスの間でデータの受け渡しを行う用途**で使用するためのファイルと言えます。
これも特殊(スペシャル)ファイルですので、パイプ自体はあくまで「門」として働くだけで、実際に読み書きするデータを保管するのはあくまで OS ( kernel ) 内部です。ファイルシステム上には保存されません。

例えば、あるコマンドの結果を小文字→大文字変換するような単純なコマンドの例として次のようなものが考えられます。

```shell_session:パイプライン実行例
$ whoami | tr a-z A-Z
ANGEL
```

この時、データを中継するパイプは、pipefsと呼ばれるパイプだけを管理する専用の ( OS内部で管理される仮想的な ) ファイルシステム上で、名前なしのファイルとして作成されます。そのため、直接パイプをファイル操作するのは困難です。

しかし、通常のファイルシステム上でも「名前付きの」ファイルとしてパイプを作成することはでき、それにより同等の機能を利用できます。

```shell-session:名前付きのパイプでデータの受け渡しを行う例
$ mknod tmp-pipe p
$ ls -l tmp-pipe
prw-rw-r--. 1 angel angel 0  9月 15 16:40 tmp-pipe
$ whoami > tmp-pipe &
[1] 31738
$ disown %1
$ tr a-z A-Z < tmp-pipe
ANGEL
```

このように名前付きのパイプは、先ほどのパイプライン実行と同じような連携を行うこともでき、かつファイル自体が表に見えていますので、どこから操作するのかに大きな自由度があります。
しかし逆に言えば、統制なしに同じパイプに各プロセスからデータが殺到すると、混じりあって混乱を招く可能性があります。その他無名のパイプに比べ、使う時には注意する点があります。

なお、mknod は様々な種類のファイルを作成する機能を持ったコマンドであり、名前付きパイプも作成することができます。

## ソケット
### ソケットの概要
ソケットは、「通信を行うための拠点となる」特殊なファイルです。
「通信」と一口に言っても実感し辛いところですが、それこそ様々な方法の通信があるところ、まとめてファイルとして扱うための存在がソケットだと見た方が良いでしょう。

パイプと同様、一般には無名のファイルとして、ファイルシステム上には見えない存在ですが、特定の通信方法に限っては「名前付き」のソケットをファイルとして作成することもできます。
`ls -l`コマンドで出力すると、行頭のファイルの種類が`s`で表されます。

```shell-session:lsでのソケットの出力
$ ls -l /dev/log
srw-rw-rw-. 1 root root 0  9月 14 19:52 /dev/log
```

### ソケットの機能
ソケットもパイプと同じく通常は無名のファイルとして、こちらは sockfs という専用のファイルシステムで管理されます。
異なるプロセス間でデータのやり取りができるということもあわせ、ソケットとパイプは機能的に似ている面があります。そのため、両者を対比するのが分かり易いかもしれません。次の図に示す点が主な違いです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74396/80e178df-0a16-0a5e-800d-2b2def4814da.png)

ポイントとしては、次のようになります。

* 使用するファイルの数  
  パイプが1つのファイルを読み書き双方で共有するのに対し、ソケットは通信するそれぞれで別々に用意し、その間をOSが仲介する形式となります。
* 連携できる範囲  
  パイプによるデータのやり取りは同一マシン内に限られますが、ソケットによる通信は、通信方式にもよりますが、同じマシン内に限りません。
* データのやり取りの方向性  
  1つのパイプは必ず読み込み側と書き込み側に分かれる、1方向のやり取りになりますが、ソケット通信では1つずつのソケットで双方向の通信に対応しています。

それ以外にも、( 図にはありませんが ) パイプでのデータのやり取りには特に「種類」の区別がないのに対し、ソケットでは多数の通信の種類が存在しています。
有名どころとしては、TCP/IPを利用した通信であるIPソケットが挙げられます。
この種類は、一般のファイル操作APIではなくソケット通信用のAPIで調整するもので、そういう意味ではその他のファイルとは一線を画す存在と言えます。

ところで、ソケット通信では2つのソケットが連携する形を取りますので、どうしても通信相手のソケットを識別する方法が必要です。
IPソケットの場合は、IPアドレス・ポート番号が使われるわけですが、同一マシン内の通信に特化したUNIXドメインソケットの場合は、ソケットにファイル名を付けることで識別させることもできます。

1例として、Linux上でsyslogによるログ管理に使われる`/dev/log`というソケットと、そのソケットに対してログを送信する logger というコマンドがあります。
次のコマンド例のように、loggerコマンドによってログを記録することができます。

```shell-session:loggerによるログ記録の例(CentOS7)
# logger hogehoge  # hogehoge という内容を送信
# tail -n 1 /var/log/messages
Sep 15 19:36:46 cent7 root: hogehoge
```

この時、構成によって様々ですが `/dev/log` から読み込みを行うログ管理サーバアプリ ( syslogデーモンや、journald ) が予め稼働していて、loggerコマンドからのログ送信を受け付けている形になります。( 次図参照 )

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74396/ab3d7c44-2b5c-5984-2bc1-d492c42e929b.png)

上で挙げたIPソケットやUNIXドメインソケット以外にも、ネットワークインターフェースを直に操作するのも同じ ( 別種の ) ソケットです。他にも様々な種類のソケットがあります。
しかし各機能をカバーするのは本記事の手に余りますので、ここでは割愛します。

# おまけ
## procfsの特殊な機能
ext4,xfs といった、ディスク装置上に構築するファイルシステムは、ユーザ、各種アプリが保存したデータの内容がストレートに保存されますが、その内容がそういった保存データと直結しない特殊なファイルシステムとして、procfsがあります。

procfs は、OS ( kernel ) の各種内部情報を操作するための専用のファイルシステムであり、様々な機能を持っています。

### レギュラーファイルを経由したOS内部の情報の参照
procfs内の、読み込み可能なレギュラーファイルは、なんらかOS内部の情報を参照する機能を持っています。

例えば、`/proc/loadavg`というレギュラーファイルを読み込むと、システムのロードアベレージ情報を取得することができます。これは uptime コマンド等で得られるロードアベレージ情報と同じです。

```shell-session:procfsによるロードアベレージ情報の参照
# ls -l /proc/loadavg
-r--r--r--. 1 root root 0  9月 14 19:16 /proc/loadavg
# cat /proc/loadavg  # ロードアベレージ情報を参照するためのファイル 
0.03 0.05 0.05 2/153 5314
# uptime   # 上の loadavg ファイルの内容を活用しているコマンド
 19:44:41 up  1:31,  2 users,  load average: 0.03, 0.05, 0.05
```

こういったファイルは、どこかディスク上にデータが保存されているわけではありません。読み込み要求に応じて、OS が動的にデータを作り出しているものです。

### レギュラーファイルを経由したOSの操作
逆に、書き込み可能なレギュラーファイルで、OSの操作を行えるものもあります。

例えば `/proc/sysrq-trigger` というレギュラーファイルは、マジックSysRqキー ( キーボード上のSysRq や PrtSc キーを使って、OSの強制再起動等を行うキーシーケンス ) の機能を代行できるものです。

以下のように、このファイルは読み込み操作はサポートせず、書き込み操作によって強制再起動等を実現することができます。
※本当に再起動しますので、もし実機で試す場合は十分にご注意ください。

```shell_session:procfsによる強制再起動操作
# ls -l /proc/sysrq-trigger
--w-------. 1 root root 0  9月 14 19:16 /proc/sysrq-trigger
# cat /proc/sysrq-trigger  # 読み込み操作ができないファイル
cat: /proc/sysrq-trigger: 入力/出力エラーです
# echo b > /proc/sysrq-trigger  # 書き込みによるマジックSysRqキーと同等の再起動指示 
→ 強制再起動のため応答なし
```

つまり、ファイルへの書き込み操作が、データの保存を目的としたものでなく、あくまでOSへの操作内容の通知として使わているのです。

### プロセスに応じた動的なディレクトリ
procfsでは、ディレクトリに登録されたファイルも動的に管理されています。

次のように `/proc` を ls コマンドで参照すると、数字だけのディレクトリが大量に出力されるのが分かります。

```shell-session:procfs内の数字だけのディレクトリ
# ls -l /proc
合計 0
dr-xr-xr-x.  9 root           root                         0  9月 14 19:52 1
dr-xr-xr-x.  9 root           root                         0  9月 14 19:52 10
dr-xr-xr-x.  9 root           root                         0  9月 14 19:52 11
dr-xr-xr-x.  9 root           root                         0  9月 14 19:52 1124
dr-xr-xr-x.  9 root           root                         0  9月 14 19:52 1125
…
```

これはご存知の通り、現在動作しているプロセスのPIDを名前とするディレクトリが動的に生成され、プロセスの情報を参照する ( 一部プロセスの操作を行う ) 各種ファイルへのアクセスパスとなっているものです。

参照できる情報は多岐に渡りますが、よく使うものとしては、コマンドライン情報を参照できる `cmdline` というファイルがあります。
次のように、PIDを指定して ps コマンドでもコマンド情報を得ることもできますが、`/proc/プロセスID/cmdline`ファイルを読むことでも情報を得ることができるのです。

```shell_session:プロセスのコマンドラインの参照
# ps -p 1 -o pid,args
  PID COMMAND
    1 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
# tr \\0 \\n < /proc/1/cmdline 
/usr/lib/systemd/systemd
--switched-root
--system
--deserialize
22
```

### 使用中のファイルを参照するシンボリックリンク
前項のプロセス毎のディレクトリの中には、そのプロセスが使用しているファイルの情報を反映したシンボリックリンクもあります。

例えば、次のように `ping localhost > ping.log` コマンドを実行すると、pingコマンドはシェルから引き継いだ端末デバイス(PTY)、リダイレクト先のファイル`ping.log`、pingの利用するIPソケットを使用している状態になります。

これを`/proc/プロセスID/fd/`というディレクトリを参照することで、使用しているファイルをシンボリックリンクの参照先として知ることができるのです。

```shell-session:pingコマンドの使用するファイルの情報
# ping localhost > ping.log &
[1] 19710
# ls -l /proc/19710/fd/  # シンボリックの形で一覧管理
合計 0
lrwx------. 1 root root 64  9月 15 21:50 0 -> /dev/pts/0
l-wx------. 1 root root 64  9月 15 21:50 1 -> /tmp/ping.log
lrwx------. 1 root root 64  9月 15 21:50 2 -> /dev/pts/0
lrwx------. 1 root root 64  9月 15 21:50 3 -> socket:[147393]
```

しかも、これらのシンボリックリンクを利用して、そのファイルの実体に触れることもできます。
例えば、ls の `-L` オプションを追加することで、確かに各ファイルの種類が出ています。
※ 端末デバイス…キャラクタデバイス、`ping.log`…レギュラーファイル、IPソケット…ソケット

```shell-session:シンボリックリンクの参照先の情報を出力
# ls -l -L /proc/19710/fd/
合計 4
crw--w----. 1 root tty  136, 0  9月 15 21:50 0
-rw-r--r--. 1 root root    950  9月 15 21:50 1
crw--w----. 1 root tty  136, 0  9月 15 21:50 2
srwxrwxrwx. 1 root root      0  1月  1  1970 3
```

更に、このシンボリックリンクを利用すると、使用中でありながら削除済みとなったファイルにアクセスすることもできます。

```shell-session:削除済みファイルへのアクセス
# rm -f ping.log
# ls -l /proc/19710/fd/
合計 0
lrwx------. 1 root root 64  9月 15 21:50 0 -> /dev/pts/0
l-wx------. 1 root root 64  9月 15 21:50 1 -> /tmp/ping.log (deleted)
lrwx------. 1 root root 64  9月 15 21:50 2 -> /dev/pts/0
lrwx------. 1 root root 64  9月 15 21:50 3 -> socket:[147393]
[root@cent7 tmp]# more /proc/19710/fd/1
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.087 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.141 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.125 ms
…
```

なお、`ls -l`コマンドで、シンボリックリンクの参照先が`/tmp/ping.log (deleted)`や`socket:[147393]`となっているように、無名のファイルや、ファイルシステム上から消えたファイルに関しては、実際の名前ではなく代わりとなる名前が出るようになっています。

## 上の分類以外のファイル
本記事では、ファイルの種類を7つ紹介しました。
※ レギュラーファイル、ディレクトリ、シンボリックリンク、ブロックデバイス、キャラクタデバイス、パイプ、ソケット、それぞれ `ls -l` での種類の出力は `-`,`d`,`l`,`b`,`c`,`p`,`s`

しかし実は、それ以外の種類のファイルもあるのです。
`ls -l` での出力は次のように`?`となります。これは一体なんでしょうか?

```text:種類が?なファイル
?rw-------  1 root root       0  9月 14 21:32 3
```

これは、無名のパイプや無名のソケットと同様、名前のないファイルに関する情報が出力されたものです。
通常は名前のないファイルの情報を出力することはできませんが、上述のprocfsでのシンボリックリンクの機能により実体の情報を参照すると、このように`?`と分類されるのです。

例えば、CentOSのPID 1番、systemd からは次のような無名ファイルの存在を見て取ることができます。

```shell_session:systemdの使う無名ファイル
# ls -l -L /proc/1/fd/{3,4,5,51}
?rw------- 1 root root 0  9月 14 21:32 /proc/1/fd/3
?rw------- 1 root root 0  9月 14 21:32 /proc/1/fd/4
?rw------- 1 root root 0  9月 14 21:32 /proc/1/fd/5
?rw------- 1 root root 0  9月 14 21:32 /proc/1/fd/51
# ls -l /proc/1/fd/{3,4,5,51}
lrwx------. 1 root root 64  9月 14 19:52 /proc/1/fd/3 -> anon_inode:[timerfd]
lrwx------. 1 root root 64  9月 15 16:24 /proc/1/fd/4 -> anon_inode:[eventpoll]
lrwx------. 1 root root 64  9月 15 16:24 /proc/1/fd/5 -> anon_inode:[signalfd]
lr-x------. 1 root root 64  9月 15 16:24 /proc/1/fd/51 -> anon_inode:inotify
```

いずれも、参照先は無名ファイル anon_inode として出力されます。その中でも様々種類があります。詳細は割愛しますが、何らかのイベント待ちや通知を管理するためのファイルとなっています。
※従来は別のAPIでイベント待ちが実現されていたものが、ファイルのI/O待ちで統一的に扱えるようになり、作られたファイルの種類が多いです。

今回は読み書きの機能を中心に説明してきましたが、ファイルの操作には他にも様々なものがあり、これらファイルはその一端を垣間見させるものとなっています。

# 終わりに
通常の利用ではあまり縁がないかもしれませんが、実際には様々な種類のファイルがあります。意識して見るようにすると、ファイルを通じてLinux自体の理解も深まるのではないでしょうか。