Linuxコマンドの作り方

## はじめに
Linuxコマンドの実体を理解するために、Linuxコマンドの作り方を調べました。  
Linuxコマンドは主にC言語で実装されたプログラムです。  
プログラムを所定のディレクトリに実行可能ファイルとして準備し、そのファイルを呼び出すことでコマンドを実行できます。  

## 環境
Ubuntu 22.04.2 LTS

## 手順の流れ
1. [ソースファイルの作成](#1-ソースファイルの作成)
2. [実行可能ファイルの作成（ソースファイルのコンパイル）](#2-実行可能ファイルの作成ソースファイルのコンパイル)
3. [実行可能ファイルの権限確認](#3-実行可能ファイルの権限確認)
4. [コマンドサーチパスの確認](#4-コマンドサーチパスの確認)
5. [実行可能ファイルの配置](#5-実行可能ファイルの配置)
6. [コマンド実行](#6-コマンド実行)

## 手順

### 1. ソースファイルの作成  
任意のディレクトリにhello.cというソースファイルを作成します。  
- コンソール
```shell_session
# ソースファイルの作成
$ cat << EOF > hello.c
#include <stdio.h>

int main(void)
{
  printf("Hello World!\n");
  return 0;
}
EOF
```

- ファイルの中身
```c:hello.c
#include <stdio.h>

int main(void)
{
  printf("Hello World!\n");
  return 0;
}
```

### 2. 実行可能ファイルの作成（ソースファイルのコンパイル）  
C言語で作成したソースファイルをgccコマンドでコンパイルします。  
-oオプションで指定したファイル名がコマンド名になります。

```shell_session
$ gcc hello.c -o hello
```

:::note alert  
gcc: command not foundと出力される場合
gccコマンドが存在しない場合は、gccコマンドが含まれているbuild-essentialパッケージをapt-getコマンドでインストールします。

- エラーメッセージ
```shell_session
$ sudo gcc hello.c -o hello
-bash: gcc: command not found
```
- build-essentialパッケージのインストール
```shell_session
$ sudo apt-get update
$ sudo apt-get install -y build-essential
```
:::

### 3. 実行可能ファイルの権限確認  
実行可能ファイルに実行権限が付与されていることを確認します。  
gccコマンドで作成されたファイルには自動的に実行権限が付与されます。
```shell_session
$ ls -l hello
-rwxr-xr-x 1 ubuntu ubuntu 15960 May 20 08:21 hello
```

:::note alert  
実行可能ファイルに実行権限がない場合
実行権限（x）が付与されていない場合は、chmodコマンドで実行権限を付与します。

```shell_session
$ ls -l hello
-rw-r--r-- 1 ubuntu ubuntu 15960 May 20 08:21 hello
# 実行権限の付与（実行権限（x）が付与されていない場合は、chmodコマンドで実行権限を付与）
$ chmod +x hello
$ ls -l hello
-rwxr-xr-x 1 ubuntu ubuntu 15960 May 20 08:21 hello
```
:::

### 4. コマンドサーチパスの確認  
PATHという環境変数に格納されている値（コマンドサーチパス）を確認します。  
Linuxはコマンドが実行されるとコマンドと同名の実行可能ファイルをコマンドサーチパスから検索して実行します。  
そのため、作成した実行可能ファイルはコマンドサーチパスへ配置する必要があります。  
実行可能ファイルはコマンドサーチパスの左側から順番に検索されるため、同名ファイルが複数のパスに存在した場合は、コマンドサーチパスのより左側にあるパス内のファイルが実行されます。  
```shell_session
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
$ echo $PATH | sed s/:/\\n/g
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
/snap/bin
```

### 5. 実行可能ファイルの配置  
実行可能ファイルをコマンドサーチパス（/usr/local/bin）へ配置します。  

```shell_session
sudo cp -p hello /usr/bin/
```

コマンドサーチパスの使い分けは基本的に以下となります。  
自作のコマンドは/usr/local/binへ配置します。

- [コマンドサーチパスの使い分け](https://linuc.org/study/knowledge/544/)  

| PATH            | 用途                                                                                                              |
| --------------- | --------------------------------------------------------------------------------------------------------------- |
| /bin            | 「シングルユーザモードでも利用できるコマンド」を配置<br>※シングルユーザモードは、基本的にOSが壊れて正常に起動できないなど非常時に利用するものです                                      |
| /usr/bin        | 「シングルユーザモードで利用しない」かつ<br>「RPMやdebなどのパッケージ管理システムによって、システムに管理されるコマンドやプログラム」を配置                                     |
| /usr/local/bin  | 「シングルユーザモードで利用しない」かつ<br>「RPMやdebなどのパッケージ管理システムによって、システムに管理されないコマンドやプログラム」を配置<br>自作のスクリプトなどはこのディレクトリに置くことが一般的です。 |
| /sbin           | /binと同様の用途 かつ システム管理用のコマンドやプログラムを配置                                                                                           |
| /usr/sbin       | /usr/binと同様の用途 かつ システム管理用のコマンドやプログラムを配置                                                                                           |
| /usr/local/sbin | /usr/local/binと同様の用途 かつ システム管理用のコマンドやプログラムを配置                                                                                           |

### 6. コマンド実行
コマンドを実行します。

```shell_session
$ hello
Hello World!
```

## 参考
- build-essentialパッケージ
https://packages.ubuntu.com/focal/build-essential

- 「/bin」「/usr/bin」「/usr/local/bin」ディレクトリの使い分け  
https://linuc.org/study/knowledge/544/