Linux 端末 シェル コマンド 基礎

# はじめに

- コマンドを入力する
- コマンドの実行結果を出力する

これらのインターフェースを提供するソフトウェアを **端末エミュレータ** という。

【代表的な端末エミュレータ】

- コマンドプロンプト（Windows）
- ターミナル（macOS）

端末エミュレータは、その言葉の通り **物理的な端末を模倣（emulate）したソフトウェア** である。

terminal は訳すと「端末」だが、物理的端末ではなく端末エミュレータを指して使われることが多い。terminal は「末端の、終着駅」などの意味も含む。

また「端末」は広義の意味では「ユーザがシステムと対話するためのインターフェース全般」を指す場合もある。

このように、歴史的に用途や姿形が大きく変化してきたために、文脈やその人の背景知識によって異なるものを指す用語がいくつかあるので、理解を深めたい。

- [端末](#かつての端末tty)
- [コンソール](#かつてのコンソール)
- [端末エミュレータ](#現代の端末--端末エミュレータ)
- [ターミナル](#ターミナル)

## かつての端末（TTY）
Terminal

原始的な入出力機器から構成される物理的装置。

- 入力装置
    - タイプライタ
- 出力装置
    - プリンタ
    - 媒体は紙

![ASR-33_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/0faefc71-57ad-4525-a725-24a9e029da81.jpeg)

> 出典：Dominic Alves from Brighton, England - ASR 33 Teletype, CC 表示 2.0
https://commons.wikimedia.org/w/index.php?curid=4259023による

現代で「入出力装置」と言えば、キーボードとディスプレイであるが、かつてはタイプライタとプリンタ（印字機）であり、この時代の端末は **TTY**（teletypewriter） と呼ばれた。

**端末自身は CPU やメモリなどといった、コンピュータとして計算を実行するための能力を持たない**。

この頃の端末は、接続された大型コンピュータへの文字入力や印字といったデータの送受信のみを行うシンクライアント的な存在だったと言える。

元来、端末と大型コンピュータは別々に存在していたが、コンピュータがどんどんと小型化していくと同時に端末装置が端末エミュレータとしてソフトウェア化され、さらに端末エミュレータ自体もコンピュータに搭載されたため、もはや両者は明確に区別することが難しくなった。

:::note info
物理的端末装置はコマンドを解釈しない。
端末エミュレータもコマンドを解釈しない。
:::

## かつてのコンソール
    
コンピュータ初期のメインフレームと呼ばれる大型コンピュータは、キーボードとディスプレイで構成される [端末](#かつての端末tty) に直に接続されていた。

この構成における「計算」はメインフレーム上で行われ、端末はメインフレームに入力を与える、メインフレームが出力した計算結果を表示する役割を担っていた。

このとき特に、端末上でオペレータ（管理者）が操作する黒の専用画面は **コンソール** と呼ばれた。

![IBM_2260.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/e90213b7-80df-4ff3-894d-16d93b294487.jpeg)

> IBM - https://digitaltmuseum.no/011015240147/22-0-ibm-modell-360-370, CC 表示-継承 4.0
https://commons.wikimedia.org/w/index.php?curid=113477774による

コンソールは **CUI** 環境であるため、[ターミナルアプリ](#端末エミュレータ) のようなウィンドウ、タブ、マウス操作という GUI 的な機能は備えていない。

![DEC_VT100_terminal.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/b1a73a5c-7d04-4bcb-b69a-84129be84d94.jpeg)

> 出典：Jason Scott - Flickr: IMG_9976, CC 表示 2.0
https://commons.wikimedia.org/w/index.php?curid=29457452による

またコンソールは **カーネルに直結している** という大きな特徴を持つ。

ケーブルを途中で抜き差しすることは想定されておらず、

- 1 台のコンピュータ（メインフレーム）
- 1 つの端末
- 端末上の 1 つの専属コンソール
- 1 人の専属オペレータ

といった 1 対 1 の対応関係で設計されていた。

## 現代のコンソール（仮想コンソール、TTY）

現代のコンソールは、かつてのコンソールを仮想化したものである。

仮想化の利点は、本来、端末上に 1 つしかないコンソールを同時に複数扱える点にある。

![Screenshot 2025-02-18 at 20.08.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/783fc8bc-34d1-4203-92f6-55b1b59187d7.png)

仮想化された現代のコンソール画面も、かつてのコンソール同様に黒い画面であることには変わりないが、**内部ではカーネルが `/dev/tty1` 〜 `/dev/tty6` の [デバイスファイル](https://qiita.com/AsahinaKei/items/09ee7ce55b1a0be01ff0#%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB) として管理している**。

かつてのコンソールはコンピュータ（ディスプレイ）とコンソールが一体化しているため、ディスプレイに映し出されるのは常に 1 つのコンソールであるが、仮想コンソールは同じディスプレイ上に映し出されるコンソールを `Ctrl + Alt + F1` 〜 `F6` で切り替えることができる（macOS の場合 `command + fn + F1` ）。

![LPIC (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/d060cb64-006b-4b1d-b01e-52b48043de03.png)



どの仮想コンソールがディスプレイに映し出されているのかは  [`$ tty`](https://qiita.com/AsahinaKei/items/301b88e464c23aba231e#-tty) によって確認することができる。

`$ tty` は現在のシェルプロセスの [標準入出力](https://qiita.com/AsahinaKei/items/301b88e464c23aba231e) が接続されたデバイスファイルを表示するコマンドである。

```console:現在のシェルプロセスの標準入出力が接続されたデバイスファイルを表示する
$ tty
/dev/tty1
```

```console:Ctl + Alt + F2 で仮想コンソールを tty1 から tty2 へ切り替えた場合
$ tty
/dev/tty2
```

`/dev/ttyX` は [`getty`](https://qiita.com/AsahinaKei/items/e354a3814639aeac4138#getty) によって標準入出力と接続される。

## 現代の端末 / 端末エミュレータ

Terminal Emulator

[物理端末](#かつての端末tty) をソフトウェアによって模倣（emulate）したアプリケーション。

- macOS の **ターミナル**
- Linux の **GNOME Terminal**
- Windows の **コマンドプロンプト**

（Windows の `cmd.exe` は端末エミュレータに分類されるが、PowerShell は本来シェルでありながら独自の端末環境を提供する。一方、Windows Terminal はこれらをホストする端末エミュレータとして動作する。）

![Screenshot 2025-02-19 at 20.22.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/1dc6417d-3e09-43c3-9eea-7fd511d0fc36.png)

かつての物理端末と同様に、**端末エミュレータ自体はコマンドを解釈、実行する機能を持たない**。

端末エミュレータは、キーボードを介してユーザーからテキスト形式で入力されたコマンドを [シェル](#シェル) に渡し、その後、実行結果をシェルから受け取りユーザに表示する。

端末エミュレータの標準入出力は、ユーザが起動したアプリケーションとしてのターミナルプロセスが仲介しており、実際には [疑似端末（**PTY**）](#擬似端末--pty) を通じてシェルと通信している。

コマンドによる CUI 操作でも、実際にはウィンドウ、タブ、ペイン操作、マウス操作、コピー＆ペーストなどができる **GUI 環境上で動作している**。Wikipedia ではこの状況を 「**GUI 環境内で CLI（コマンドライン・インタフェース）を提供する**」 と上手に表現されていた。

**コンソールは完全な CUI 環境で動作する** ため、混同しがちな「ターミナルアプリ」と「コンソール」の大きな違いの一つがこの点にある。

[デスクトップ環境](https://qiita.com/AsahinaKei/items/63085a778cbdd29dad4a#%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E7%92%B0%E5%A2%83) のない環境では、端末エミュレータは存在しない。一方、デスクトップ環境のない環境でも仮想コンソールは存在する。

端末エミュレータは、複数のタブを開くことができ、タブごとにシェルを立ち上げることができる。
    
![Screenshot 2025-02-20 at 7.59.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/00cb5c45-bec3-4230-ab0b-651d12f93d64.png)


[ウィンドウシステム](#ウィンドウシステム) を搭載しているデスクトップ環境では、アプリケーションとしての端末エミュレータを複数起動させることもできる。

![Screenshot 2025-02-20 at 7.57.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/1b91cbcc-c9ca-4fba-920f-d7f21c759106.png)

また端末エミュレータに各種製品が存在し、動作する環境や特徴が異なる。

| アプリケーション名 | 動作する環境 | 特徴 |
|:-|:-|:-|
| ターミナル | macOS | macOS 標準搭載。<br>[Bash](#bash---bash) や [Zsh](#zsh) などのシェルへアクセスできる。 |
| iTerm2 | macOS | サードパーティ製。<br>タブ分割、複数ペイン表示、ショートカットなどの機能、カスタマイズ性が豊富。 |
| xterm | X Window System | Unix 系 OS（特に Linux）で利用される。<br>カスタマイズ性が低いが軽量で動作が軽く、基本機能に特化している。<br>リソースが少ない環境や古いシステムでの使用に適している。 |
| GNOME Terminal | X Window System | GNOME デスクトップ環境に標準搭載。<br>高度なカスタマイズ機能を持つ。 |
| Windows Terminal | Windows | Windows 11 から標準搭載。<br>Windows 10 ではインストールが必要。 |
| コマンドプロンプト | Windows | Windows 標準搭載。 |

端末エミュレータは、ローカルマシンの OS 上でシェルを動作させるだけでなく、SSH などを利用してネットワーク経由でリモート環境のサーバのシェルに接続し、操作する用途にも使われる。

## 擬似端末 / PTY
pseudo terminal

従来の [物理的な端末](#かつての端末tty) を擬似的に再現した端末のこと。または端末エミュレータ上で論理的に分割された接続セッションのこと。

**擬似端末（PTY）という概念を導入することで、1台のPC上で複数の端末（セッション）を並行して操作・利用することが可能になる**。

擬似端末はカーネルによって `/dev/pts/0` や `/dev/pts/1` のような [デバイスファイル](https://qiita.com/AsahinaKei/items/09ee7ce55b1a0be01ff0#%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB) として作成される。

**PTY** は **マスター** と **スレーブ** のペアによって構成される。

- マスター（Master）
    - `/dev/ptmx`
    - スレーブに対して指示を出したり、スレーブからの出力を受け取る
    - 端末をエミュレートするプログラム側（[`$ ssh`](https://qiita.com/AsahinaKei/items/17d802e0c3ace8004a85#-ssh)、`$ screen`、`$ tmux`、端末エミュレータなど）
    - UI を担当
    - 主従関係を表す用語が差別的な表現であることから、現代では **コントローラ** と呼ばれることもある
- スレーブ（Slave）
    - `/dev/pts/N`
    - 実際にシェルやコマンドが接続され、標準入出力をマスターに渡している裏方
    - 端末としての振る舞いを担当
    - シェルが標準入出力として利用する

ユーザからのコマンド入力は端末エミュレータからマスターに渡り、スレーブを経由してシェルへ送信される。

反対にコマンドの実行結果は、シェルからスレーブが受信し、マスターを経由して端末エミュレータに届けられる。

このように擬似端末は、仮想的に端末（TTY）をエミュレート（再現） しているにすぎない。

以下のコマンドで内部的に利用される。

- [`$ tmux`](#-tmux)
- [`$ screen`](#-screen)

## ターミナル

macOSに標準搭載されている [端末エミュレータ](#端末エミュレータ)。

文脈によっては、端末エミュレータそのものを指す場合がある。


# シェル

コマンドを解釈して、カーネルに対する [システムコール](#システムコール) を実行するソフトウェア。

[シェルスクリプト](https://qiita.com/AsahinaKei/items/615316c04d32b34e9fa8#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB) を解釈し、実行するインタプリタ。

シェルは GUI を持っていないので、私たちは端末エミュレータが提供するインターフェース（CLI）を介してシェルを利用している。

Windows の PowerShell のように、シェルが端末エミュレータと一体になっているものもある。

具体的には Bash、Zsh、sh などのプログラムがシェルである。

| 種類 | 特徴 |
|:-|:-|
| Bash | Unix 系システムで広く使用される |
| Zsh | 高度な機能とカスタマイズ性を持つ |
| sh | 古い Unix シェルの一つ |
| コマンドライン（`cmd.exe`） | Windows コンソールホスト上で動作<br>MS-DOS 由来のコマンドが多い |
| Power Shell | コマンドラインの後継<br>GUI を持つため、端末エミュレータでもある<br>オブジェクト指向 |

ログイン直後に起動されるシェルは [ログインシェル](#ログインシェル) と呼ばれる。

端末エミュレータを介してシェルに渡されたコマンドは、シェルによって起動された [子プロセス](https://qiita.com/AsahinaKei/items/e354a3814639aeac4138#%E8%A6%AA%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9--%E5%AD%90%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9) 上で実行される。

```console:シェルが子プロセスを生成する
$ コマンド
```

シェルが動作しているプロセス上でコマンドを実行したい場合には、[`$ source`](#-source---) や [`$ .`](#-source---) などのコマンドを使用する。

```console:シェルが子プロセスを生成しない
$ source コマンド
$ . コマンド
```

## Bash / `$ bash`
Bourne Again Shell

Unix 系システムで広く使用されている標準シェル。[POSIX](#posix) 規格に準拠しており、ほとんどの Unix 系システムで動作する。

Bash は `$ bash` コマンドで起動できる。

```console:Bash を起動する
$ bash
```

私の環境は macOS なので、デフォルトでは Zsh がログインシェルになっている。

特定のシェルとの対話（ログイン ~ ログアウトまで）を **セッション** と表現することがあり、Zash が Bash を起動した場合、Bash による新しいシェルセッションが開始されることとなる。

```console:Zsh から Bash を起動する
$ echo $0 # ログイン中のシェルを確認する
-zsh

$ bash
The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.

bash-3.2$  # Bash のシェルセッションが開始される
```

起動した Bash は `$ exit` で終了できる。

シェルとの対話（セッション）を開始せずに、特定のスクリプトを実行させることもできる。

```console:スクリプトを Bash 上で実行する
$ bash スクリプト
```

## Zsh / `$ zsh`
Z Shell

高度な機能とカスタマイズ性を持つシェル。Bash と同様に [POSIX](#posix) 規格に準拠している。

近年の macOS のデフォルトシェル。

`$ bash` と同様に、新しいシェルセッションを開始することができる。

```console:Zsh を起動する（新しいセッションを開始する）
$ zsh
```

```console:スクリプトを Zsh 上で実行する
$ zsh スクリプト
```

## sh
Bourne Shell

古くから存在するUnixシェルの一つで、他の多くのシェル（Bash、Zsh など）の基礎となっている。

「sh」と言う用語は、シェルスクリプトやコマンドを示すための一般的な総称として使われることがあり、Bash、Zsh、sh で記述されたスクリプトファイルの拡張子には `.sh` が使用される。

## POSIX
Portable Operating System Interface

IEEE によって策定される Unix 系 OS 間での互換性を保つための規格。

開発者目線では、POSIX 規格に従って開発することでプログラムが異なる OS 間で移植可能になる。また、Windows OS は POSIX には準拠していない（WSL といった技術は提供されている）。

さまざまなサブ規格に分かれている。

## プロンプト `$` / `%` / `#`
prompt=促す

端末エミュレータが提供する CLI において、ユーザに対してコマンドの入力を促す文字列や記号のこと。

シェルが表示させている。

プロンプトが表示中は、コマンド入力を受付中であり、プロンプトが表示されていない間は何らかのプロセスが実行中であることを意味する。

シェルによって特定の記号が特別な意味を持つ場合がある。

| 記号 | 意味 |
|:-:|:-|
| `$` | [一般ユーザ](https://qiita.com/AsahinaKei/items/59c380a98c65d0aef887#%E4%B8%80%E8%88%AC%E3%83%A6%E3%83%BC%E3%82%B6) としてログイン中であることを示す |
| `#` | スーパーユーザ（管理者）としてログイン中であることを示す |
| `%` | Zsh 等で利用される |

プロンプトとして表示される文字列は [ビルトインシェル変数](#ビルトインシェル変数)の `$PS1`、`$PS2` でカスタマイズすることができる。

# カーネル
Kernel

以下に挙げられるようなシステムの基幹となる制御を行う **OSの中核** 部分を担うソフトウェア。

- [プロセス](https://qiita.com/AsahinaKei/items/e354a3814639aeac4138) 管理
- メモリ管理
- [デバイス](https://qiita.com/AsahinaKei/items/09ee7ce55b1a0be01ff0#%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB) 管理
- [ファイルシステム](https://qiita.com/AsahinaKei/items/09ee7ce55b1a0be01ff0) の管理
- [アクセス](https://qiita.com/AsahinaKei/items/2fbc4e079b1c4b847240) 制御



ハードウェアとソフトウェアの橋渡し的な役割を持つ。

通常、アプリケーション（プロセス）は、カーネルから提供されるインターフェースを介してのみ、デバイス（ハードウェア）へのアクセスが許されている。

![software (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/f03e40b4-7e19-4376-8b4b-8ae5878cf300.png)


この制限によって、デバイスに複数のプロセスが同時にアクセスする場合でも、カーネルが競合するアクセス要求を調停するため、アプリケーション間でリソースの競合が起きない仕組みになっている。

カーネルがアプリケーションに提供するインターフェースや、機能を利用するために呼び出す命令または関数を [システムコール](#システムコール) 、スーパーバイザコール（**SVC**：supervisor call）という。このインターフェースは、ハードウェアの仕様の違いに依存しないように抽象化されている。

## カーネルモード / ユーザモード

CPU の動作モードには、**カーネルモード** と **ユーザモード** がある。

カーネルモードは、その名の通りカーネルのプロセスが動作したり、デバイスドライバなどのプロセスが動作したりするモードであり、 **特権モード** とも呼ばれる。

カーネルモードの CPU は、メモリ、I / O デバイスなどのハードウェアリソースに、制限なくアクセスを行うことができる。そのため、カーネルモードで不正な操作が行われたりバグが発生すると、メモリが破壊されたりデバイス動作が停止するといった、システム全体に影響が出る。

一方ユーザモードは、通常のアプリケーションプログラムが動作するモードであり、直接ハードウェアにアクセスを行うことができない。ユーザモードで動作するプロセスは、カーネルの提供するシステムコールを介してハードウェアにアクセスする。

## システムコール

カーネルから提供される、プロセスがカーネルの特権的な機能を呼び出すためのインターフェース。

- ファイル操作： `open`, `read`, `write`
- プロセス管理： `fork`, `exec`, `kill`
- ネットワーク通信： `socket`, `connect`

https://syscalls.mebeim.net/?table=x86/64/x64/latest

システムコールは、ユーザモード で動作中の CPU をカーネルモードへ遷移させる手段でもある。

システムコールの実行が終了すると、CPU はカーネルモードから再びユーザモードに戻ってプロセスの実行を継続する。

システムコールを呼び出すことができるプログラミング言語は複数ある。

- C言語
- アセンブリ言語
- Rust
- Go
- Python
- C++
- Perl
- Ruby
- AssemblyScript / WebAssembly

C言語やアセンブリ言語は、OS　やカーネル開発において主要言語として採用されることが多い。一方、Python や Perl などはシステムコールを直接呼び出す用途ではなく、ラッパーやモジュール経由で利用することが多い。

C言語には、`glibc` と呼ばれる [標準Cライブラリ](#標準cライブラリ) が存在し、この中にはシステムコールを内部的に呼び出すラッパー関数が含まれている。アセンブリ言語は直接システムコールを呼び出すことができるものの、[アーキテクチャ](https://qiita.com/AsahinaKei/items/63085a778cbdd29dad4a#%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3) ごとに存在するシステムコールを環境に応じて呼び分ける必要がある。C言語では `glibc` のようなラッパー関数がアーキテクチャごとの違いを吸収するため、呼び出し側はその違いを意識する必要がない。

## 例外

プロセスがシステムコールを発行すると、CPU において **例外** が発生する。

この例外をトリガーにして、CPU は ユーザモード から カーネルモード へ遷移し、システムコールの処理を行う。

システムコールの処理が終了すると、CPU は再びユーザモードに戻り、プロセスを継続する。

## 標準Cライブラリ

C言語に標準で付属しているライブラリ。

[システムコール](#システムコール) のラッパー関数が含まれ、`glibc` （GNU C Library）とも言う。

- 入出力操作（`printf`, `scanf`）
- メモリ管理（`malloc`, `free`）
- ファイル操作（`fopen`, `fread`, `fwrite`）
- システムコールのラップ（`open`, `read`, `write`）

| システムコール | 標準Cライブラリのラッパー関数 | 説明 |
|:-|:-|:-|
| `open` | `open`  | ファイルを開く |
| `read` | `read` | ファイルやデバイスからデータを読み取る |
| `write` | `write` | ファイルやデバイスにデータを書き込む |
| `close` | `close` | ファイルを閉じる |

# コマンド

シェルに対する命令。[端末エミュレータ](#端末エミュレータ) への入力を介して実行する。

**コマンドの実体は実行可能ファイル**であり、実行可能ファイルにはバイナリ形式とスクリプト形式（テキスト）がある。

:::note info
コマンドの実体はバイナリ形式、もしくはテキスト形式の実行可能ファイル
:::

その他、以下のような形式もある。

- [ビルトインコマンド](#ビルトインコマンド)
- [エイリアス](#エイリアス)
- [関数](#関数)

## 実行可能ファイル（バイナリ形式）

バイナリ形式の実行可能ファイル。

バイナリ形式とは、「0」「1」の二進数で表現されたデータ形式のこと。

実行可能ファイルとは、[実行権限](https://qiita.com/AsahinaKei/items/2fbc4e079b1c4b847240#%E3%82%B7%E3%83%B3%E3%83%9C%E3%83%AA%E3%83%83%E3%82%AF%E5%BD%A2%E5%BC%8F) のあるファイルのこと。

バイナリ形式の実行可能ファイルは、具体的には C 言語などのコンパイル形式のプログラミング言語で記述されたプログラムをコンパイルしたものを指す。コンパイル形式の言語にはその他 C++、Rust、Go などがある。

バイナリ形式の実行可能ファイルをコマンドとして実行した場合、そのプロセスは **呼び出したシェルとは別プロセスとして実行される**。

この形式のコマンドの代表例には `$ ls`、`$ grep`、`$ cat` などがある。

Linux にはバイナリ形式の実行可能ファイルに拡張子をつけない習慣があり、上記のコマンドの実体はそれぞれ、`/bin/ls`、`/usr/bin/grep`、`/bin/cat` などの拡張子の付かないファイルとして存在している。

私を含む Linux の初学者は、コマンドを使い始めた頃、使っているコマンドの実体がファイルであることを意識しないと思う。それは多分、バイナリ形式の実行可能ファイルは絶対パスで実行することもできるし、ファイル名だけでも実行することができるからだと思う。

```console:絶対パス
$ /bin/ls
```

```console:ファイル名
$ ls
```

なぜファイル名を入力しただけで、シェルがファイルを探し当てることができるのかについては、[環境変数](#環境変数) `$PATH` の存在を理解する必要がある。

`$PATH` には通常以下のような値が設定されている。

```console:$PATH
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
```

`$ ls` が実行された時、シェルはまずこのリスト内から `ls` ファイルがないかを探している。

もし環境変数 `$PATH` に `/bin` が設定されていない場合には、シェルは `ls` ファイルを見つけることができず、ファイル名だけでコマンドを実行することはできない。一方で、ビルトインコマンドは `$PATH` を使用しないので、設定がなくても実行することができる。

※ 正確には下記の順に検索が行われる
1. エイリアス
1. ビルトインコマンド
1. 環境変数 `$PATH`

なお、`$PATH` にはカレントディレクトリを含めることができないため、カレントディレクトリ上の実行可能ファイルを実行するには `./` に続けてファイル名を指定する必要がある（`.` はカレントディレクトリを表す）。

```console:カレントディレクトリ上の実行可能ファイル
$ ./ファイル名
```

また「ビルトインコマンド」は **内部コマンド** と呼ばれることがあるのに対して、「バイナリ形式の実行可能ファイル」を **外部コマンド** と呼ばれる。

## 実行可能ファイル（スクリプト形式）

スクリプトファイルは実行権限を付与することで、[スクリプト](https://qiita.com/AsahinaKei/items/615316c04d32b34e9fa8#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB) としてシェルから実行することができる。

コマンドとしてファイル名だけで実行させるためには、スクリプトファイルに読み取り権限（`r`）と 実行権限（`x`） を付与する必要がある（バイナリ形式のファイルの場合、実行権限のみで良い）。

```console:カレントディレクトリのスクリプトを実行する
$ ./スクリプトファイル # 読み取り権限と実行権限が必要
```

一方で、[`$ bash`](#-bash) や [`$ source`](#-source---) の引数に渡して実行する場合には、読み取り権限（`r`）だけで実行できる。

```console:読み取り権限だけでOK
$ bash スクリプトファイル
$ source スクリプトファイル
$ . スクリプトファイル
```

スクリプトの記述方法については [こちら](https://qiita.com/AsahinaKei/items/615316c04d32b34e9fa8)。

## ビルトインコマンド

シェルに組み込まれたコマンド。**内部コマンド** と呼ばれることもある。

シェルによって直接実行されるため、**呼び出したシェルのプロセス内で実行される**。

代表的なものに `$ cd`、`$ pwd`、`$ echo`、`$ alias`、`$ export` などがある。

```console:ビルトインコマンド
$ type cd
cd is a shell builtin
```

[バイナリ形式の実行可能ファイル](#実行可能ファイルバイナリ形式) とは異なり、環境変数 `$PATH` を気にする必要がない。

## 関数

シェルスクリプトで定義した関数はコマンドのように実行することができる。

関数は `$ function` によって定義し、[`$ unset`](#-unset) で削除することができる。

```console:関数
$ function say_hello() { echo "hello world"; }
$ say_hello
hello world
```

シェルスクリプトを実行した場合に子プロセスが生成されるのに対して、関数を実行した場合には子プロセスは生成されない。

## エイリアス

既存のコマンドには **エイリアス** と呼ばれる「別名」をつけて実行することができる。


## `$ which`

```console:コマンドの実行可能ファイルの絶対パスを表示する
$ which コマンド名
```

```console:例
$ which ls
/bin/ls
```

※ `$PATH` に記載がないディレクトリにあるコマンドは表示されない

## `$ whereis`

```console:コマンドの実行可能ファイル（バイナリファイル）、ソースコード、マニュアルファイルのパスを検索する
$ whereis コマンド名
```

```console:例
$ whereis ls
ls: /bin/ls /usr/share/man/man1/ls.1
```

## `$ whatis`

コマンドのマニュアルページの説明部分を 1 行で簡易表示させる。

```console:コマンドの簡易説明を表示する
$ whatis コマンド名
```

マニュアルをすべて表示したい場合には [`$ man`](#-man) を使う。

表示される `(数字)` はマニュアルのセクション番号を表す。

```console:
$ man ls
ls (1)               - list directory contents
```

## `$ type`

```console:コマンドがビルトインコマンドか、実行可能ファイルか調べる
$ type コマンド名
```

```console:例
$ type ls
ls is /bin/ls

$ type cd
cd is a shell builtin
```

[`$ kill`](https://qiita.com/AsahinaKei/items/e354a3814639aeac4138#-kill) コマンドのように、ビルドインコマンドと実行可能ファイルの両方を持つものもある。

## `$ command`

[ビルトインコマンド](#ビルトインコマンド) と [外部コマンド](#実行可能ファイルバイナリ形式) を使い分ける際に利用される。

`$ command` 自体はビルトインコマンド。

同じ名前のコマンドにビルトインコマンドと外部コマンドがある場合、通常はビルトインコマンドが優先して使用される。

このようなとき、`$ command` を利用することで明示的に外部コマンドを実行することができる。

```console:外部コマンドを実行する
$ command コマンド
```

他にも、外部コマンドと同名の [エイリアス](#エイリアス) が設定されている場合に、エイリアスを無視して外部コマンドを優先して実行させることができる。

## `$ alias`

登録済みエイリアスは `$ alias` で表示することができる。

```console:エイリアスを一覧表示する
$ alias
```

新たにエイリアスを定義する際は、次のようにエイリアス名とコマンド名を `=` で指定する。

```console:エイリアスを定義する
$ alias エイリアス名=コマンド
```

```console:例
$ alias hello='echo "hello world"'
$ hello
hello world
```

セミコロン `;` を使うと、複数のコマンドを集約させることもできる。

```console:複数のコマンドにエイリアスをつける
$ alias hello='echo "hello";echo "bye"'
$ hello
hello
bye
```

引数にエイリアス名を指定すると、エイリアスにしたコマンドを表示することができる。

```console:指定されたエイリアスの中身を表示する
$ alias エイリアス名
```

```console:例
$ alias hello
hello='echo "hello world"'
```

`$ alias` コマンドで登録したエイリアスは、**現在のシェルセッションでのみ有効** であるため、永続的なエイリアスを登録したい場合、シェルの [環境設定ファイル](#設定ファイル) に定義を追加する。

Bash を使用している場合 `~/.bashrc` という環境設定ファイルがシェル起動時に読み込まれているため、このファイルに以下の１行を追加しておくことで永続的なエイリアスを追加することができる。

```text:~/.bashrc
alias hello='echo "hello world"'
```

編集した `~/.bashrc` ファイルは端末エミュレータを再起動するか、[`$ source`](#-source---) コマンドを使って、シェルに再読み込みさせることができる（[`$ source` と `$ bash` の違い](#-source-と--bash-との違い) ）。

```console:環境設定ファイルを再読み込みさせる
$ source ~/.bashrc
```

## `$ unalias`

```console:エイリアスを削除する
$ unalias エイリアス名
```


## `$ function`

```console:関数を定義する
$ function 関数名() { 処理; }
$ 関数名() { 処理 }
```

※ `function` で定義する場合、処理の末尾にはセミコロン `;` を記載する

## `$ history`

```console:コマンドの実行履歴を表示する
$ history
履歴番号 コマンド
```

`$ !履歴番号` とすることで、指定した履歴コマンドを再度実行させることができる。

```console:指定した履歴番号のコマンドを実行
$ !履歴番号
```

```console:直前の履歴コマンドを実行
$ !!
```

```console:検索ワードにヒットするコマンドを実行
$ !検索ワード
```

Bashの場合 [`~/.bash_history`](#) にコマンド履歴が保存され、保存できる履歴の最大数はビルトインシェル変数 [`$HISTSIZE`](#ビルトインシェル変数)、`$HISTFILESIZE` で設定できる。

また、`Ctrl` + `R` の同時押しでコマンド履歴を検索することもできる（*reverse-i-search*：逆順インクリメンタル検索）。

```console:Ctrl + R を同時押しで検索モードに切り替える
$ # Ctrl + R を押す
bck-i-search: _
```

検索モードからは `Ctrl` + `G` もしくは `Esc` で戻ることができる。

```console:コマンド履歴の検索
$ # ←ここに検索ワードを入力する
bck-i-search: _
```

検索にヒットした履歴は、再び `Ctrl` + `R` を押すことでさらに過去のヒット結果に移ることができる。

履歴の位置は保存されるため、`Ctrl` + `G` で検索を終了した時、`↑` や `↓` を押すと、ヒットした履歴の位置からの表示になる。

## `$ eval`

引数とした渡された文字列をコマンドとして実行するためのコマンド。

```console:引数に渡された文字列をコマンドとして実行する
$ eval "コマンド"
```

## `$ apropos`

```console:指定したキーワードを含むマニュアルページを検索する
$ apropos キーワード
```

## `$ man`
manual

コマンドのマニュアルページを表示する。

```console:マニュアルを表示する
$ man コマンド名
```

表示されたマニュアルは `Q` キーで終了できる。

実際には「コマンド」のマニュアルだけでなく、設定ファイル、ライブラリ、システムコールなどのマニュアルページも検索、表示することができる。

```console:検索ワードに合致するマニュアルページを表示する
$ man 検索ワード
```

```console:完全一致検索（$ whatis と同じ）
$ man -f 検索ワード
```

```console:部分一致検索（$ apropos と同じ）
$ man -k 検索ワード
```

[`$ whatis`](#-whatis)、[`$ apropos`](#-apropos)

マニュアルページには **セクション** と呼ばれる分類があり、セクション番号があらかじめわかっている場合、番号を指定して検索を行うことができる。

```console:セクション番号で範囲指定して検索
$ man セクション番号 検索ワード
```

| セクション | 内容 |
|:-:|:-|
| 1 | 一般コマンド（一般ユーザが使用する） |
| 2 | [システムコール](#システムコール)（カーネルが提供する API） |
| 3 | [標準Cライブラリ](#標準cライブラリ) |
| 4 | [デバイスファイル](https://qiita.com/AsahinaKei/items/09ee7ce55b1a0be01ff0#%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB) |
| 5 | [設定ファイル](#設定ファイル) |
| 6 | ゲーム、スクリーンセーバー |
| 7 | その他 |
| 8 | システム管理コマンド（`root` ユーザ向け） |
| 9 | Linux 独自のカーネル用ドキュメント |

## `~/.bash_hisotry`

[`$ history`](#-history) が参照するコマンドの実行履歴が格納されたファイル。

履歴情報は `シェルの起動時` に `~/.bash_hisotry` から読み出される。

また `シェルにログイン中` もしくは `セッション中` は、シェルプロセス内のメモリ上に保持され、コマンド実行の都度 `~/.bash_hisotry` へ書き込まれているわけではない。

最後にログアウト、セッション終了時に `~/.bash_history` へ再び書き込まれる。

この挙動は「複数のタブを開いて操作」した場合に、[複数のタブにまたがって実行したコマンド履歴が、時系列順に表示されない](#複数のタブにまたがるコマンド履歴--prompt_command) 現象を引き起こす。

## `/usr/share/man/`

[`$ man`](#-man) が参照するファイル。

Linux ディストリビューションに含まれる、パッケージのマニュアルドキュメントの格納ディレクトリ。

## `/usr/local/share/man/`

[`$ man`](#-man) が参照するファイル。

Linux ディストリビューションに含まれない、ユーザが後からインターネット経由などで追加したパッケージのドキュメント格納ディレクトリ。

## コマンド置換

`$()` でコマンドを囲うと、コマンドの実行結果を文字列に展開して、別のコマンドの引数として渡すことができる。

古い記法としてバックコーテーション ``` `` ``` を利用した方法もあるが、可読性が低くなるため `$()` の使用が推奨されている。

```console:コマンド置換
$ echo $(コマンド)
$ echo `コマンド` # ` はバックコーテーション
```

[文字列中の変数の展開](#変数の展開) 同様に文字列内でも展開することができるが、シングルコーテーション内では展開されないため注意。

```console:文字列中のコマンド置換
$ echo "ls: $(ls)"
$ echo "ls: `ls`"

$ echo '$(ls)' # コマンド置換されない
```

:::note info
`'` シングルコーテーションで囲った文字列中のコマンドは展開されない
:::


## 複数のコマンドを続けて実行する

`;` で複数のコマンドを続けて実行させることができる。コマンド実行結果にかかわらず、後続のコマンドは実行される。

```console:;
$ コマンド1; コマンド2; コマンド3
```

`&&` では、コマンドが正常終了した場合のみ、後続のコマンドが実行される。

```console:&&
$ コマンド1 && コマンド2 && コマンド3
```

`||` では、コマンドが異常終了した場合のみ、後続のコマンドが実行される。

```console:||
$ コマンド1 || コマンド2 || コマンド3
```

`()` で複数のコマンドをまとめることもできる。

```console:()
$ (コマンド1; コマンド2; コマンド3) && コマンド4
```

## 複数行のコマンド入力

複数行のコマンドを入力したい場合、行末にバックスラッシュ `\` を記述する。

```console:複数行のコマンド入力
$ echo \
$ "hello world"
hello world
```


## 一時的にエイリアスを無効化する

既存のコマンドと重複するエイリアスが設定されている場合、通常はエイリアスの方が優先される。

`/` をコマンドの前につけることで、エイリアスを一時的に無効化することができる。

```console:エイリアスを一時的に無効化し、エイリアスではない方のコマンドを実行する
$ /コマンド
```

## 複数のタブにまたがるコマンド履歴 / `$PROMPT_COMMAND`

[`~/.bash_hisotry`](#bash_hisotry) の挙動は「複数のタブを開いて操作」した場合に、複数のタブにまたがって実行したコマンド履歴が、時系列順に表示されない現象を引き起こすことがある。

これは、コマンド履歴がタブごとに保持され、後から閉じたタブが先に閉じたタブが書き込んだ履歴を上書きするためである。

厳密にはコマンド履歴はシェルのプロセスごとに保持されている。タブが異なれば、起動しているシェルプロセスも異なるため、コマンド履歴は結果的にタブごと別々に保持されていることとなる。

![LPIC (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/d1f5670c-fa45-41ec-a5b3-a1cebcf1d7b0.png)

![LPIC (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/7c2fc451-d97e-44e3-984b-a8395d1580d2.png)

コマンド履歴を即時反映させたい場合には [`$PROMPT_COMMAND`](#ビルトインシェル変数) に以下を追加する。これにより、コマンド実行の度に `~/.bash_history` が更新させることができる。

```console:コマンドの実行履歴を即時反映させる
$ export PROMPT_COMMAND="history -a; history -n" 
```

```console:シェルプロセスがメモリ上に保持するコマンド履歴を直ちに ~/.bash_history に追記する
$ hostory -a
```

```console:他のタブが追記した履歴をすぐに読み込み直す
$ history -n
```


# 変数

## シェル変数

ログイン中のシェルセッションでのみ有効な変数。

**親プロセスから子プロセスへ引き継がれない**。

```shell-session:変数を宣言する
$ 変数名=値
```

```shell-session:変数を参照する
$ $変数名
```

```shell-session:例
$ hello=こんにちは
$ echo $hello
こんにちは
```

## ビルトインシェル変数

シェルであらかじめ宣言されている変数。

| ビルトインシェル変数 | 説明 |
|:-|:-|
| `$0` | 実行中のシェルの名前、もしくはコマンド名やスクリプトファイルのパス<br>【覚え方】0 番目の引数→起動名 |
| `$1`,`$2`,`$3`... | シェルスクリプト内もしくは関数内で、渡された引数が順に格納される（1番目は `$0` ではなく `$1`）<br>【覚え方】n 番目の引数 |
| `$*`,`$@` | シェルスクリプト内で、スクリプトに渡されたすべての引数を取得する際に使用<br>`$*`：一つの文字列として格納<br>`$@`：文字列の集合として格納（スペース区切り）<br>【覚え方】全部の引数 |
| `$#` | シェルスクリプト内で、スクリプトに渡された引数の数<br>【覚え方】引数の数 |
| [`$?`](#終了ステータス--) | 直前の実行コマンドの終了ステータス<br>成功の場合は `0`、失敗の場合は `0` 以外の値が自動的に格納される<br>【覚え方】うまくいった`?` |
| `$$` | 実行中のシェル自身のプロセスID |
| `$!` | 最後にバックグラウンドで生成されたコマンドのプロセスID |
| [`$PS1`](#) | プロンプトとして表示する文字列の定義（prompt string） |
| [`$PS2`](#) | セカンダリプロンプト（複数行入力時の表示）として表示する文字列の定義 |
| [`$PROMPT_COMMAND`](#複数のタブにまたがるコマンド履歴--prompt_command) | プロンプトが表示される直前に実行されるコマンド |
| `$HISTFILE` | コマンド履歴を保存するファイルのパス<br>デフォルト値：[`~/.bash_history`](#bash_hisotry) |


## 環境変数

**親プロセスから子プロセスに引き継がれる変数**。

環境変数を介して情報を参照することで、シェルまたはシステム全体で情報を共有することができる。

システム全体で利用する環境変数は、シェル起動時に実行される [`/etc/bash.bashrc`](#etcbashbashrc) ファイル（Bash の場合）にて `$ export` を実行する。

ユーザ固有の環境変数は [`~/.bashrc`](#bashrc) にて `$ export` する。

**ただし、これらの設定ファイル はシェルの起動時にしか読み込まれないため、シェル起動後にファイルを編集した場合は [`$ source`](#-source---) コマンドによって再読み込みさせる必要がある**。

また、スクリプト内でも `$ export` を使って環境変数を設定することはできるが、その環境変数はスクリプト内でのみ有効であり、スクリプトが終了すると使用することはできない。つまり、**変数は親シェルに対して反映させることはできない**。

もしスクリプトから呼び出し元のシェル（親プロセス）でも有効な環境変数を設定したい場合、`$ source スクリプト` という形で、スクリプトを現在のシェル上で実行する必要がある。

| 環境変数 | 説明 |
|:-|:-|
| `$PATH` | [実行可能ファイル](#実行可能ファイルバイナリ形式) の検索パス<br>複数のパスが `:` で区切られた文字列として格納される |
| `$HOME` | ユーザのホームディレクトリのパス<br>チルダ `~` でも取得可能 |
| `$PWD` | 現在の作業ディレクトリ |
| `$OLDPWD` | `$ cd` で移動する前の作業ディレクトリ |
| `$SHELL` | 現在使用されているシェルのパス（`/bin/bash`、`/bin/zsh`など） |
| `$LANG` | ロケール |

## カーネル変数

カーネルの動作を制御するための設定値。

カーネル変数の変更は、動作中のカーネルに対して即時反映される。

`$ sysctl` を使用して確認、変更することができる。

また、カーネル変数は `/proc/sys/` ディレクトリ配下のファイルを介して、確認、変更することもできる。

```console:カーネル変数を確認する
$ sysctl -a # すべて表示
$ sysctl 変数名
$ cat /proc/sys/ファイル名 
```

```console:カーネル変数を変更する（一時的）
$ sysctl -w カーネル変数名=値
$ echo 値 > /proc/sys/ファイル名
```

カーネル変数の変更を永続的に行いたい場合、`/etc/sysctl.conf` を編集する必要がある。

```plaintext:/etc/sysctl.conf のフォーマット
カーネル変数名 = 値
```

| カーネル変数 | パス | 説明 |
|:-|:-|:-|
| `net.ipv4.ip_forward` | `/proc/sys/net/ipv4/ip_forward` | パケットのフォワーディング（ルータ機能の有効化） |
| `net.ipv4.icmp_echo_ignore_all` | `/proc/sys/net/ipv4/icmp_echo_ignore_all` | [`$ ping`](https://qiita.com/AsahinaKei/items/8accc0c2ecc73e0f56d9#-ping---ping6) への反応を無効化 |
| `net.ipv4.conf.all.rp_filter` | `/proc/sys/net/ipv4/conf/all/rp_filter` | 逆方向パケットフィルタの設定（IP スプーフィング対策） |
| `vm.swappiness` | `/proc/sys/vm/swappiness` | スワップ使用の閾値。<br>低いほど物理メモリが優先される |
| `fs.file-max` | `/proc/sys/fs/file-max` | システム全体の最大オープンファイル数 |


## `$ set`

実行中のシェル環境内で定義された全ての以下変数を表示する。

- シェル変数
- ビルトインシェル変数
- 環境変数

```console:全ての変数を表示する
$ set
```

`-o` / `+o` オプションによってシェルの機能を有効化したり無効化することができる。

`-` が有効化、`+` が無効化であり、個人的には直感に反している気がしたが、古来の Bash の文化、慣習らしい。

```console:指定した機能を有効化する
$ set -o 対象機能
```

```console:指定した機能を無効化する
$ set +o 対象機能
```

| 対象機能 | 説明 |
|:-|:-|
| `errexit` | コマンドがエラーを返した時に、即座にスクリプトを終了する |
| `nounset` | 未定義の変数を使用した場合にエラーを発生させる |
| `xtrace` | 実行するコマンドを表示（スクリプトのデバッグ用） |
| `verbose` | コマンドの内容をそのまま表示 |
| `noexec` | コマンドの実行をせずに構文チェックのみを行う |		

現在の設定を確認することもできる。

```console:シェルの現在の設定を確認する
$ set -o
```

<details><summary>実行結果</summary>

```console:シェルの現在の設定を確認する
$ set -o
allexport      	off
braceexpand    	on
emacs          	on
errexit        	off
errtrace       	off
functrace      	off
hashall        	on
histexpand     	on
history        	on
ignoreeof      	off
interactive-comments	on
keyword        	off
monitor        	on
noclobber      	off
noexec         	off
noglob         	off
nolog          	off
notify         	off
nounset        	off
onecmd         	off
physical       	off
pipefail       	off
posix          	off
privileged     	off
verbose        	off
vi             	off
xtrace         	off
```
</details>

現在の設定を復元するためのコマンド一覧を表示することもできる。

```console:設定復元用のコマンド一覧を表示する
$ set +o
```

<details><summary>実行結果</summary>

```console:設定復元用のコマンド一覧を表示する
$ set +o
set +o allexport
set -o braceexpand
set -o emacs
set +o errexit
set +o errtrace
set +o functrace
set -o hashall
set -o histexpand
set -o history
set +o ignoreeof
set -o interactive-comments
set +o keyword
set -o monitor
set +o noclobber
set +o noexec
set +o noglob
set +o nolog
set +o notify
set +o nounset
set +o onecmd
set +o physical
set +o pipefail
set +o posix
set +o privileged
set +o verbose
set +o vi
set +o xtrace
```
</details>


## `$ unset`

シェル変数、関数定義を削除する。

```console:シェル変数、関数を削除する
$ unset 変数名
$ unset 関数名
```

## `$ declare`

変数に特定の属性（型や制約）を設定することができる。

```console:変数を定義する
$ declare 変数名=値
```

| オプション | 説明 |
|:-|:-|
| `-i` | 変数を整数型に制限する<br>整数以外の値を代入すると `0` 扱いになる |
| `-r` | 読み取り専用の変数にする（再代入不可） |
| `-x` | 環境変数としてエクスポートする（`$ export` と同じ） |
| `-f` | 定義された関数を一覧表示する |
| `-F` | 定義された関数名を一覧表示する |


## `$ export`

シェル変数を環境変数として設定する。環境変数となった変数は、子プロセスに引き継がれる。

```console:シェル変数を環境変数に設定する
$ export 定義済みシェル変数名
```

```console:例
$ hello="こんにちは"
$ export hello
```

シェル変数を定義すると同時に環境変数として宣言することもできる。

```console:新たに定義するシェル変数を環境変数に設定する
$ export 環境変数名=値
```

```console:例
$ export PATH="/some/directory:$PATH"
```

この時の末尾の `:$PATH` は、既存の `$PATH` の先頭に追記をするためのもの。誤って上書きしてしまわないよう注意が必要。


設定ファイルに `$ echo` とリダイレクト演算子 [`>>`](https://qiita.com/AsahinaKei/items/301b88e464c23aba231e#-1) を利用して追記することもできる。

```console:Bash
$ echo 'export PATH="/some/directory:$PATH"' >> ~/.bashrc
```

## `$ printenv`

```console:環境変数の一覧を表示する
$ printenv 
```

```console:指定した環境変数の値を確認する
$ printenv 環境変数名
```

## `$ env`

環境変数を表示したり、一時的な環境変数を設定しながら別のコマンドを実行する。

単に `$ env` とした場合、`$ printenv` と同様に環境変数の一覧が表示される。

```console:一覧を表示する
$ env
```

下記のように記述すると、現在のシェルプロセスには影響を与えず子プロセス内でのみ有効な環境変数を設定することができる（[こちら](#子プロセスの環境変数を設定する) を参照）。

```console:一時的に環境変数を設定してコマンドを実行する
$ env 環境変数名=値 コマンド
```

```console:環境変数を全て削除した環境でコマンドを実行する
$ env -i コマンド
```

## 変数の展開

変数を展開したい場合は、`$変数名` もしくは `${変数名}` とする。

コマンドの引数、条件式、配列展開などシェルスクリプトのさまざまな場所で適用することができる。

```console:シェル変数を展開する
$ echo $変数名
$ echo ${変数名}
```

文字列リテラル中でも使用することができる。

```console:文字列中でシェル変数を展開する
$ echo "hello $変数名"
$ echo "hello ${変数名}"
```

ただし文字列リテラルで使用する場合、`'` シングルコーテーションで囲った文字列中の変数は展開されないため注意）

:::note info
`'` シングルコーテーションで囲った文字列中の変数は展開されない
:::


特に、パスのようにスペースを開けずに変数を使用したい場合は `${変数名}` を使用する。

```console:例
$ hello=こんにちは

$ echo $hello
こんにちは

$ echo "$hello"
こんにちは

$ echo "$hello world"
こんにちは world

$ echo "$helloworld" # 変数 helloworld が未定義のため、何も出力されない

$ echo "${hello}world"  # 変数に続いてスペースなしで文字列を使用する場合
こんにちはworld
```

## 子プロセスの環境変数を設定する

コマンドを実行する際に、変数宣言をコマンドの前に置くことで、実行されるコマンド（子プロセス）でのみ有効な環境変数を設定することができる。

これにより、現在のシェルプロセスには影響を与えずに環境変数を利用することができる。

```console:子プロセスで有効な環境変数を設定する
$ 環境変数名=値 コマンド
```

[`$ env`](#-env) を利用した場合も同じ。

```console:一時的に環境変数を設定してコマンドを実行する
$ env 環境変数名=値 コマンド
```

## 終了ステータス / `$?`

直前の実行コマンドの終了ステータス。`0` ~ `255` が使用可能。

- 成功: `0`
- 失敗: `0 以外`

自作のスクリプトで終了ステータスを呼び出し元に返すには、`$ exit` コマンドを使用する。

```console:終了ステータス
exit 0    # 正常終了（成功）
exit 1    # 異常終了（エラーなど）
```

これを利用して、異常が発生したらスクリプトを終了させることができる。

```bash:異常が発生したらスクリプトを終了させる
if [ $? != 0 ]; then 
    exit 1;
fi
```

エラー発生後に `$ echo` コマンドで `$?` を確認した場合、`$ echo` コマンドの成否が `$?` に再代入される点に注意。

```console:続けて echo $? を実行した場合
$ cd not_exixts_directory
cd: no such file or directory: not_exixts_directory

$ echo $?   # $? には cd コマンドの終了ステータスが格納されている
1

$ echo $?   # $? には直前の echo コマンドの終了ステータスが格納されている
0
```

## `$PS1` / `$PS2`

[コマンドプロンプト](#プロンプト-----) として表示される文字列の設定。

以下の特殊文字（エスケープシーケンス）を使用することができる。

| 特殊文字 | 意味 |
|:-:|:-|
| `\u` | ユーザ名 |
| `\h` | ホスト名（[`/etc/hostname`](https://qiita.com/AsahinaKei/items/8accc0c2ecc73e0f56d9#etchostname) で設定） |
| `\w` | 現在の作業ディレクトリ |
| `\$` | [ユーザの種類](https://qiita.com/AsahinaKei/items/59c380a98c65d0aef887#%E3%83%A6%E3%83%BC%E3%82%B6%E3%81%AE%E7%A8%AE%E9%A1%9E)（`$`：一般ユーザ、`#`：`root` ユーザ） |
| `\s` | シェルの名前 |
| `\v` | シェルのバージョン |

セカンダリプロンプトは、[コマンドを複数行にまたがって入力](#複数行のコマンド入力) する場合に表示される。

```console:セカンダリプロンプト
$ コマンド \
セカンダリプロンプト
```

デフォルトでは `$PS1='[\u@\h:\w]\$'`、`$PS2='>'` のようになっていることが多い。



# ログインシェル / 対話型シェル

[シェル](#シェル) は役割の違いによって **ログインシェル** や **対話型シェル** と呼び分けられることがある。

## ログインシェル

**ログインして最初に起動されるシェル**。

ログインを必要とするので、シェル起動時にユーザアカウントの **パスワードの入力が要求される**。

ログインシェルには以下がある。

- [仮想コンソール](#現代のコンソール仮想コンソールtty) で **ログイン** したとき
- [`$ ssh`](https://qiita.com/AsahinaKei/items/8accc0c2ecc73e0f56d9#-ssh) で **ログイン** したとき
    - `$ ssh ユーザー名@ホスト`
- 明示的にログインシェルを起動したとき
    - `$ bash --login`
- ログインユーザを指定してシェルを起動した時
    - `$ su - ユーザー名`（`$ su` だけだとログインシェルにならない）
    - 厳密には「ログイン後、最初に起動されるシェル」ではないが、設定ファイルの読み込みの挙動がログインシェルとしての振る舞いを見せる

ログインシェルでは、起動（ログイン）時は以下の順に [設定ファイル](#設定ファイル) が読み込まれる。

```shell:例：ログインシェル
/etc/profile
↓
~/.bash_profile
↓
(~/.bash_login)
↓
(~/.profile)
```

終了（ログアウト）時は [`~/.bash_logout`](#bash_logout) が読み込まれる。

ログインシェルを Bash にするのか Zsh にするのかの設定は、[`/etc/passwd`](https://qiita.com/AsahinaKei/items/59c380a98c65d0aef887#etcpasswd) で行うことができる。

## 非ログインシェル

「ログインシェルではないが、対話型シェルであるシェル」を **非ログインシェル** と呼ぶ。

ログインを行わずにシェルが起動されるため、**ユーザアカウントのパスワードが要求されない**。

非ログインシェルには以下がある。

- ターミナルアプリを開いたとき
- Bash を `--login` オプションなしで起動したとき
    - `$ bash`
    
非ログインシェルは対話型シェルの一つなので、起動時に `~/.bashrc` が実行され、その後、プロンプト表示によってインタラクティブなコマンド入力を待つ状態になるものの、ログインシェルではないため `~/.bash_profile` は読み込まれない。

ただし、環境変数は親シェル（ログインシェル）から引き継がれる。

## 対話型シェル

ユーザーが直接コマンドを入力できるシェルのこと。**インタラクティブシェル** とも呼ばれる。

大きな特徴として、プロンプトが表示され、ユーザーの入力を待つという点がある。

対話型シェルには以下がある。

- ログインシェルとして Bash を開いたとき
    - **ログインシェルは基本的に対話型シェル** でもある
    - `$ ssh ユーザー名@ホスト`
    - `$ su - ユーザー名`
    - `$ bash --login`
- ターミナルアプリを開いたとき
    - **ログインシェルではないが、対話型シェル** である状態
- 明示的に対話型シェルを起動したとき
    - `$ bash -i`（interactive）

対話型シェルでは起動の度に `~/.bashrc` が実行される。`~/.bashrc` 内では `/etc/bash.bashrc` が呼ばれることが多い。


## 非対話型シェル

スクリプトを実行するだけのシェルを **非インタラクティブシェル**（非対話型シェル） と呼ぶことがある。 

非インタラクティブシェルには以下がある。

- スクリプトが実行されるとき
    - `$ bash myscript.sh`
- シェルスクリプトが [シバン](https://qiita.com/AsahinaKei/items/615316c04d32b34e9fa8#%E3%82%B7%E3%83%90%E3%83%B3shebang-)（`#!/bin/bash`）で実行されたとき
- `$ bash -c 'コマンド'` でコマンド実行するとき

非インタラクティブシェルでは、 `~/.bashrc` は自動で読み込まれない。

そのため、非対話型シェルで実行させるスクリプト内で、エイリアスや関数を利用したい場合、`$ source ~/.bashrc` もしくは `$ . ~/.bashrc` を実行する必要がある。

## `$ chsh`
change shell

```console:ログインシェルを変更する（対話的な手続きが開始される）
$ chsh
```
    
```console:利用可能なシェルを確認する
$ chsh -l
$ chsh --list-shells
```

```console:変更後のシェルを指定する
$ chsh -s /bin/zsh
```

指定するシェルは `/etc/shells` に記載されているものである必要がある。また `$ chsh` の内部的には [`/etc/passwd`](https://qiita.com/AsahinaKei/items/59c380a98c65d0aef887#etcpasswd) にあるユーザー情報の `shell` フィールドが書き換えられている。

またログインシェルを変更した場合、次回ログインから有効となり、現在のセッションには影響しない。

## `/etc/shells`

ログインシェルとして使用可能なシェルの一覧が記載されたファイル。

```text:/etc/shells
/bin/sh
/bin/bash
/bin/zsh
/usr/bin/fish
```

# 設定

シェルには Bash や Zsh などの種類ごとに設定ファイルが存在する。

各設定ファイルは **スクリプト形式** で記述されており、それぞれ実行されるタイミングが異なる。そのため、実行されるタイミングに合わせて必要な環境設定を行うことができる。

各設定ファイルには **読み取り権限** があれば良い。

[ログインシェル](#ログインシェル) と [対話型シェル](#対話型シェル) で実行されるファイルが異なる。

起動順序は以下の通り。最初に以下のパターンを頭に入れておくと理解しやすい。

```shell:起動順のパターン
システム全体に適用される /etc/ の設定ファイル
↓
ユーザ単位で適用される ~/ の設定ファイル
↓
(上記ファイルが存在しない場合に適用される設定ファイル)
```


```shell:例：ログインシェル
/etc/profile
↓
~/.bash_profile
↓
(~/.bash_login)
↓
(~/.profile)
```

```shell:例：対話型シェル
/etc/bash.bashrc
↓
~/.bashrc
↓
(/etc/bashrc)
```

## `/etc/profile`

- 対象：ログインシェル
- 読み込まれるタイミング：OS へのログイン時
- 主な用途：システム全体の環境設定

## `/etc/bash.bashrc`
bash run commands

- 対象：対話型シェル（ログイン・非ログインに関わらず実行される）
- 読み込まれるタイミング：Bash の起動時
- 主な用途：システム全体の対話型シェル設定
    - 全てのユーザで共有される
- Debian系（Ubuntu、Debian）で利用される
- ログイン時にも実行したい場合には、`/etc/profile` 内で `$ source /etc/bash.bashrc` もしくは `$ . /etc/bash.bashrc` を実行する必要がある

## `/etc/bashrc`
bash run commands

- 対象：対話型シェル
- 読み込まれるタイミング：Bash の起動時
- 主な用途：システム全体の対話型シェル設定
    - ユーザごとにファイルが存在する
- `~/.bashrc` から呼ばれ、間接的に実行されるのが一般的
- Red Hat系（CentOS、Fedora、RHEL）で利用される

## `~/.bash_profile`

- 対象：ログインシェル
- 読み込まれるタイミング：OS へのログイン時
- 主な用途：ユーザーごとの環境設定（`Welcome ${whoami}!` のようなログイン時にだけ表示するメッセージなど）
    - ユーザごとにファイルが存在する
- ログインシェルにおいても対話型シェルの設定を利用するために、`~/.bash_profile` 内で `$ source ~/.bashrc` もしくは `$ . ~/.bashrc` するのが一般的

## `~/.bash_login`

- 対象：ログインシェル
- 読み込まれるタイミング：OS へのログイン時 
- `~/.bash_profile` が存在しない場合にのみ、実行される
    - ユーザごとにファイルが存在する

## `~/.profile`

- 対象：ログインシェル
- 読み込まれるタイミング：OS へのログイン時
- `~/.bash_profile` も `~/.bash_login` のどちらも存在しない場合にのみ、実行される
    - ユーザごとにファイルが存在する

## `~/.bashrc`
bash run commands

- 対象：対話型シェル
- 読み込まれるタイミング：Bash の起動時
    - ログインシェルの起動時に `~/.bach_profile` 内でも呼び出されるので、結果的に、シェルの起動時は必ず実行される
- 主な用途：ユーザーごとの対話型シェル設定（[エイリアス](#エイリアス) の設定など）
    - ユーザごとにファイルが存在する

## `~/.bash_logout`

- 対象：ログインシェル
- 読み込まれるタイミング：OS からのログアウト時（[`$ exit`](#-exit) 時）
- 主な用途：一時ファイルを削除したり、画面をクリアするなど
- 設定ファイルがなければ実行されない
    - ユーザごとにファイルが存在する


## `$ shopt`
Shell Options

Bash のオプションを設定するためのビルトインコマンド。

```console:現在のオプションの状態を確認する
$ shopt
```

オプション名を引数に渡すと、特定のオプションの状態を確認することができる。

```console:特定のオプションの状態を確認する
$ shopt オプション名
```

```console:制御可能なオプション一覧を表示する
$ shopt -p # s（set）で表示されたものは有効。u（unset）で表示されたものは無効。
```

現在のシェルセッションで使用中のシェルがログインシェルであるかどうかは、`login_shell` オプションを確認することで確認できる。

```console:ログインシェルかどうか確認する
$ shopt login_shell   # on ならログインシェル
login_shell     on
```

## `$SHELL`

[ビルトインシェル変数](#ビルトインシェル変数) `$SHELL` には、ユーザーのログイン時に設定されたデフォルトのシェルのパスが格納されている。

表示されたシェルは、現在動作中のシェルとは限らない。

```console:ログイン時のデフォルトのシェルを知る方法
$ echo $SHELL
/bin/zsh
```

## `$0`

[ビルトインシェル変数](#ビルトインシェル変数) の `$0` には、現在実行中のシェルまたはスクリプトの名前が格納されている。ログインシェルの場合、先頭に `-` が付く。

```console:シェルの種類を確認する
$ echo $0
-bash
```

## `$ source` / `$ .`

**指定したシェルスクリプトを現在起動しているシェルのプロセス上（現在と同じシェル環境）で実行する**。

```console:スクリプトを実行する
$ source スクリプトファイル
```

[環境設定ファイル](#設定ファイル) を編集した際に、シェルを再起動することなく反映させるために使用される。

```console:環境設定の変更を現在のシェルに適用させる
$ source ~/.bashrc
```

**`$ source` コマンドで読み込んだスクリプトは、現在起動しているシェルのプロセス内で実行される** ため、環境変数やエイリアスの設定を、起動中のシェル環境に即時適用させることができる。

またドット `$ .` もコマンドであり `$ source` と同じ機能を持つ。

```console:「.」もコマンド
$ . スクリプトファイル
```

## `$ source` と `$ bash` との違い

`$ source` と `$ bash` はどちらも引数としてスクリプトを渡して実行させることができるが、スクリプトが実行される環境には大きな違いがある。

まず、`$ source` は **呼び出したシェルと同じプロセス上で実行される**。

```console:シェルと同じプロセス上でスクリプトが実行される
$ source スクリプトファイル
```

ここで言う「呼び出し元のシェル」とは、私たちが入力したコマンドを受け付けるために

一方、`$ bash` は呼び出し元のシェルが新しいシェルプロセス（子プロセス）を起動し、渡したスクリプトは **新たに起動した Bash のプロセス（子プロセス）上で実行される**。

```console:シェルの子プロセス上でスクリプトが実行される
$ bash スクリプトファイル
```

環境変数を追加するなどした際に `~/.bashrc` を再読み込みさせようとする場面で、この違いはうまくいかない原因になることがある。

```console:現在のシェルに対して効果がない
$ bash ~/.bashrc
```

上記のコマンドは、呼び出し元のシェルプロセスには反映されない。

# 標準入出力 / リダイレクト / パイプ

https://qiita.com/AsahinaKei/items/301b88e464c23aba231e

# `$ exit`

現在のシェルプロセスを終了する。スクリプト内で実行した場合、そのスクリプトの実行を即座に終了する。

```console:現在のシェルセッションや、スクリプトの実行を終了させる
$ exit
```

引数に数値を指定することで、[終了ステータス](#終了ステータス--) を呼び出し元に返却することができる。

シェルからスクリプトを実行した場合には、スクリプトを起動したシェルに終了ステータスが返却され、シェルから別のシェルを起動し、そのシェル内で `$ exit` を実行すると、元のシェルに制御が戻り、終了ステータスが返る。

```console:終了ステータスを指定しながらシェルを終了する
$ exit 終了ステータス
```

`$ exit` コマンドの終了ステータスには、直前のコマンドの [$?](#ビルトインシェル変数) をそのまま引数として渡すこともできる。


```console:直前のコマンドの終了ステータスをそのまま親プロセスに返す
$ exit $?
```

# `$ tmux`
Terminal Multiplexer

[擬似端末](#擬似端末--pty) のセッションを管理するターミナルマルチプレクサ。

マルチプレクサ（**MUX**）は、複数の入力信号の中から1つを選択して出力するデジタル回路や装置のこと。

`$ tmux` を利用することで、1つのターミナルアプリ内で複数の擬似端末を管理することができる。

ターミナルのタブ機能やペイン機能に似た操作ができるが、これらはターミナルアプリの GUI による視覚的な管理であるのに対し、`$ tmux` は CUI による管理という違いがある。

通常、ターミナルのタブやペインに紐づくプロセスはターミナルを閉じると終了するが、`$ tmux` のセッションは `tmux` プロセスが動いている限り維持される。

また **デタッチ**、**アタッチ** という特徴的な機能がある。

さらに [`$ ssh`](https://qiita.com/AsahinaKei/items/17d802e0c3ace8004a85#-ssh) を利用したネットワーク越しの操作において、作業途中で接続が切断された場合でも、`tmux` のセッションは端末の外部で動いているので、SSH 切断の影響を受けず、サーバー上で動作し続ける。そのため、SSH 再接続後に作業を再開させることができる。


`$ tmux` コマンドの実行により、新規セッションが作成される。

```console:セッションを開始する
$ tmux
```

```console:名前付きセッションを作成する
$ tmux new -s セッション名
```

`tmux` セッション内での操作は主にキー入力によって行うことができる。

`Ctrl` + `B` を押した後に特定のキーを再び押すという順番になっていて、`Ctrl` + `B` を プレフィックスキーと言う。

| キー | 説明 |
|:-|:-|
| `Ctrl` + `B` → `C` | 新しいウィンドウを作成（Create） |
| `Ctrl` + `B` → `N` | 次のウィンドウに切り替え（Next） |
| `Ctrl` + `B` → `P` | 前のウィンドウに切り替え（Previous） |
| `Ctrl` + `B` → `&` | 現在のウィンドウを削除 |
| `Ctrl` + `B` → `%` | 垂直にペインを分割 |
| `Ctrl` + `B` → `"` | 水平にペインを分割 |
| `Ctrl` + `B` → `矢印キー` | アクティブなペインを切り替え |
| `Ctrl` + `B` → `D` | **デタッチ** |
| `$ tmux attach` | **アタッチ** |
| `$ tmux new` | 新しいセッションを作成 |
| `$ tmux new -s セッション名` | セッション名を指定して新しいセッションを作成 |
| `$ tmux list-sessions` | セッションを一覧表示 |
| `$ tmux kill-session` | セッションを終了 |
| `$ tmux kill-session -t セッション名` | 指定したセッションを終了 |

## デタッチ / アタッチ
Detach / Attach

`$ tmux` は [擬似端末](#擬似端末--pty) との接続を管理する役割を果たす。

（学習メモ：自分のようなLinux初学者には、デタッチやアタッチのイメージが非常に湧きづらかった。「計算装置（サーバ）に接続された [物理的な端末装置](#かつての端末tty)（キーボードとディスプレイ）」を頭に思い浮かべると、`tmux` のデタッチ・アタッチの動作をイメージしやすいかもしれないと思った。昔は「端末を切り替える」と言ったら、作業者が物理端末Aから物理端末Bまで移動するしかなかった。）

**デタッチ**

- 現在のターミナルから `tmux` セッションの接続を切る
- 作業者が端末の席から離れる、もしくは「ディスプレイの」電源を切るイメージ。計算装置は稼働し続ける。
- `tmux` セッション自体はサーバー上で動作し続ける
- 現在のターミナルからは操作できなくなる

**アタッチ**
- `tmux` セッションを開く
- 作業者が端末前の席に座る、もしくはディスプレイの電源を入れるイメージ。元々、計算装置は稼働している前提。
- ターミナルを通じて `tmux` セッションを操作できる状態になる

# ウィンドウシステム

GUI を提供するための基盤となるソフトウェア。

以下の機能が提供される。

- ウィンドウの移動、サイズ変更などの管理
- 入力デバイス（マウス、キーボード）の管理
- グラフィック描画の管理

## X Window System

Unix 系 OS で GUI を提供するシステム。

 **X** や **X11** と呼ばれることもある。

Linux では OS と一緒にインストールされることが多いが、技術的には OS に組み込まれている訳ではなく、独立したコンポーネントとして存在する。

**クライアント - サーバ方式** で動作している。

- **X クライアント**
    - 描画を要求するプロセス
    - 一般的な GUI アプリケーション
        - Web ブラウザ、端末エミュレータなど
    - 入力イベントをサーバから受け取り、アプリ内でイベントハンドリング処理を行う
- **X サーバ**
    - **`/usr/bin/Xorg`**
    - X クライアントからの描画要求を処理し、画面に描画する
    - **デバイス管理** を担当する
        - ディスプレイへの映像出力
        - キーボード、マウスからの入力をイベントとしてクライアントに伝達する

私たちが普段使う PC は、サーバとクライアントが同じマシン上で動作しているが、別々のマシン上で動作させることもできる。

ネットワークで繋がった X サーバーに対してウィンドウを表示させることを特に **X転送** という。X 転送は [`$ ssh -X`](https://qiita.com/AsahinaKei/items/17d802e0c3ace8004a85#-ssh--x--x%E8%BB%A2%E9%80%81) コマンドによって実現できる。

また、クライアントは `$ xhost` を使用して利用できるサーバを許可、または拒否することができる。

```console:利用できるサーバを追加する
$ xhost +ホスト名
$ xhost +   # 全て許可
```

```console:利用できるサーバを削除する
$ xhost -ホスト名
$ xhost -   # 全て拒否
```

ホストとディスプレイの紐付けは [環境変数](#環境変数) `$DISPLAY` で設定することができる。

ディスプレイ番号のデフォルト値は `0`。

```console:環境変数 DISPLAY の設定①
$ DISPLAY=ホスト名:ディスプレイ番号
$ export DISPLAY
```

```console:環境変数 DISPLAY の設定②
$ DISPLAY=ホスト名:ディスプレイ番号.スクリーン番号
$ export DISPLAY
```

クライアントとサーバは **Xプロトコル** で通信を行うので、異なる OS、ハードウェア、アーキテクチャ（CPU）同士でも動作させることができる。

X 自体にはウィンドウの装飾や配置の機能はなく、これらは [ウィンドウマネージャ](#ウィンドウマネージャ) と呼ばれる独立したプログラムによって提供される。さらに、[デスクトップ環境](https://qiita.com/AsahinaKei/items/63085a778cbdd29dad4a#%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E7%92%B0%E5%A2%83) は、ウィンドウマネージャに加えてパネルやファイルマネージャなどを統合したものである。

また近年では、X に代わって **Wayland** という新しいプロトコルが登場している。

## Wayland

X Window System の後継となるウィンドウシステム。

X と同様にクライアント-サーバ方式を採用しているが、X のように中央管理の X サーバは存在せず、**コンポジタ**（Compositor） がクライアントと直接通信する形になっている。

コンポジタは、個々のクライアントから要求されたウィンドウを **合成**（composite）してスクリーンイメージを生成する。

これにより、X よりもシンプルで効率的な描画が可能になる。

クライアントとサーバは **Wayland プロトコル** によって通信する。

ウィンドウの配置やタイトルバーの描画などの機能もコンポジタが直接管理するため、ウィンドウマネージャが存在しない点が X とことなr。

代表的な Wayland のコンポジタ
- Mutter（GNOME 用）
- KWin（KDE 用）
- Weston（Wayland のリファレンス実装）
- sway（i3 風のタイル型 Wayland コンポジタ）

## ディスプレイマネージャ

X Window System 上で動作するソフトウェアコンポーネント。

ユーザーがログインするための GUI ログイン画面の提供、セッションの管理を担当する。

![Ubuntu_22.04_login_screen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/296cc2d2-e409-4cd0-bf33-745e54bd6933.png)

ディスプレイマネージャは、ユーザー名とパスワードを入力するログイン画面を表示し、ログイン後には適切なデスクトップ環境や X サーバ（`/usr/bin/Xorg`）を起動する。

| ディスプレイマネージャ | 特徴 |
|:-|:-|
| `XDM` | X Display Manager<br>最も基本的なディスプレイマネージャ<br>シンプルなログイン画面 |
| `GDM` | Gnome Display Manager<br>GNOME デスクトップ環境に標準搭載 |
| `LightDM` | 軽量で高速<br>Ubuntu のデスクトップ環境で利用される|

[`systemd`](https://qiita.com/AsahinaKei/items/e354a3814639aeac4138#systemd) が採用された環境では、`systemd` が `display-manager.service` を起動する。


## ウィンドウマネージャ

X Window System 上で **X クライアントとして動作する** コンポーネント、ソフトウェア。

ウィンドウの配置、サイズ変更、移動、装飾（ボーダーやタイトルバー）などの管理を担当する。

代表的なものには FVWM や IceWM、Openbox、Metacity などがある。

| ウィンドウマネージャ | 特徴 |
|:-|:-|
| `Metacity` | GNOME向けのウィンドウマネージャ。<br>シンプルで使いやすい。 |
| `KWin` | KDEで使用されるウィンドウマネージャ。<br>カスタマイズオプションが豊富。 |
| `i3` | 軽量で効率的なタイル型ウィンドウマネージャ。<br>キーボードでの操作性が重視されている。 |
| `Openbox` | 軽量でカスタマイズ可能なウィンドウマネージャ。<br>デスクトップ環境に依存せず単独でも利用できる。 |